www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Lots of bool operations shouldn't compile

reply Don Clugston <dac nospam.com.au> writes:
Four examples, although it's only one bug. Almost all operations on bool 
should be disabled, but I found the ones below a little amusing. None of 
them should compile, but they all evaluate as "true".

void main()
{
     if (true >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (false >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (true <> -2i) { writefln("NCEG operators too ??!!"); }
     if (false != -2i) { writefln("and again"); }
}
Feb 28 2006
next sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Don Clugston skrev:
 Four examples, although it's only one bug. Almost all operations on bool 
 should be disabled, but I found the ones below a little amusing. None of 
 them should compile, but they all evaluate as "true".
 
 void main()
 {
     if (true >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (false >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (true <> -2i) { writefln("NCEG operators too ??!!"); }
     if (false != -2i) { writefln("and again"); }
 }

According to the specification, booleans are a numeric type. true == 1 and false == 0. So this error is not specific to bool. Try s/true/1/g and s/false/0/g and you will get the same results. The first two comparisons should be false I guess since they are unordered. The other two are correct. (If it is wise to have bool as a numeric type is a different question.) /Oskar
Feb 28 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Oskar Linde wrote:
 Don Clugston skrev:
 Four examples, although it's only one bug. Almost all operations on 
 bool should be disabled, but I found the ones below a little amusing. 
 None of them should compile, but they all evaluate as "true".

 void main()
 {
     if (true >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (false >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (true <> -2i) { writefln("NCEG operators too ??!!"); }
     if (false != -2i) { writefln("and again"); }
 }

According to the specification, booleans are a numeric type. true == 1 and false == 0. So this error is not specific to bool. Try s/true/1/g and s/false/0/g and you will get the same results. The first two comparisons should be false I guess since they are unordered. The other two are correct.

OK, there's another bug in there, comparing an int with an imaginary real should also not be legal. if (1 > -2i) { assert(0); } if (1 > ireal.nan) { assert(0); } Reals and ireals cannot be compared. Ever.
 (If it is wise to have bool as a numeric type is a different question.)

I think it's very hard to justify numeric operations on bools. (which is an _entirely_ different issue to implicit "!is null" in conditionals, I wholeheartedly support if (p), while(1){} and assert(0) ). But I note that bool b = 7; is currently disallowed, while b+=5; compiles. There's no reason to write b++, it's just letting bugs in. Write b=true instead. I hope that all such bug-breeding nonsense disappears. With a one bit integer, it wasn't clear how such things should behave (every other integral types wraps around, so b=5 should mean b=0 -- yuck!), but hopefully it can be cleared up now.
Feb 28 2006
next sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Don Clugston skrev:
 Oskar Linde wrote:
 Don Clugston skrev:
 Four examples, although it's only one bug. Almost all operations on 
 bool should be disabled, but I found the ones below a little amusing. 
 None of them should compile, but they all evaluate as "true".

 void main()
 {
     if (true >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (false >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (true <> -2i) { writefln("NCEG operators too ??!!"); }
     if (false != -2i) { writefln("and again"); }
 }

According to the specification, booleans are a numeric type. true == 1 and false == 0. So this error is not specific to bool. Try s/true/1/g and s/false/0/g and you will get the same results. The first two comparisons should be false I guess since they are unordered. The other two are correct.

OK, there's another bug in there, comparing an int with an imaginary real should also not be legal. if (1 > -2i) { assert(0); } if (1 > ireal.nan) { assert(0); } Reals and ireals cannot be compared. Ever.

You are right. I didn't notice.
 
 (If it is wise to have bool as a numeric type is a different question.)

I think it's very hard to justify numeric operations on bools. (which is an _entirely_ different issue to implicit "!is null" in conditionals, I wholeheartedly support if (p), while(1){} and assert(0) ). But I note that bool b = 7; is currently disallowed, while b+=5; compiles. There's no reason to write b++, it's just letting bugs in. Write b=true instead. I hope that all such bug-breeding nonsense disappears. With a one bit integer, it wasn't clear how such things should behave (every other integral types wraps around, so b=5 should mean b=0 -- yuck!), but hopefully it can be cleared up now.

I fully agree. (But note that the current D bool is (sans bugs) semantically identical (as far as I can tell) to C99 and C++ bool, who both allows b+=5, et.al.) /Oskar
Feb 28 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Oskar Linde wrote:

 (But note that the current D bool is (sans bugs) semantically identical 
 (as far as I can tell) to C99 and C++ bool, who both allows b+=5, et.al.)

I just tried that in MSVC, and you're right. I didn't know that. It's probably a legacy of the pre-bool days when ints or BOOL were used. In practice, I doubt it's really much of a problem. But there doesn't seem to be any rational reason to allow them. BTW, MSVC accepts bool b = true; b /= false; // crashes at run time with a div by zero error but gives a warning for bool b = true/false; // Can this be constant folded? What the heck does it set it to? Also accepts b/=6.5; Wonder what b/=real.nan does.
Mar 01 2006
parent Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Don Clugston schrieb am 2006-03-01:
 Oskar Linde wrote:

 (But note that the current D bool is (sans bugs) semantically identical 
 (as far as I can tell) to C99 and C++ bool, who both allows b+=5, et.al.)

I just tried that in MSVC, and you're right. I didn't know that. It's probably a legacy of the pre-bool days when ints or BOOL were used. In practice, I doubt it's really much of a problem. But there doesn't seem to be any rational reason to allow them. BTW, MSVC accepts bool b = true; b /= false; // crashes at run time with a div by zero error but gives a warning for bool b = true/false; // Can this be constant folded? What the heck does it set it to? Also accepts b/=6.5; Wonder what b/=real.nan does.

That's interresting: b /= 6.5; // compiles b = b / 6.5; // fails to compile Bool is an integer type and thus floats are not implicitly converted to integral types. Added to DStress as http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_A.d http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_B.d http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_C.d http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_D.d http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_E.d http://dstress.kuehne.cn/nocompile/o/opAddAssign_19_F.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_A.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_B.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_C.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_D.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_E.d http://dstress.kuehne.cn/nocompile/o/opAdd_09_F.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_A.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_B.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_C.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_D.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_E.d http://dstress.kuehne.cn/nocompile/o/opDivAssign_19_F.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_A.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_B.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_C.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_D.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_E.d http://dstress.kuehne.cn/nocompile/o/opDiv_14_F.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_A.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_B.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_C.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_D.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_E.d http://dstress.kuehne.cn/nocompile/o/opMulAssign_19_F.d http://dstress.kuehne.cn/nocompile/o/opMul_09_A.d http://dstress.kuehne.cn/nocompile/o/opMul_09_B.d http://dstress.kuehne.cn/nocompile/o/opMul_09_C.d http://dstress.kuehne.cn/nocompile/o/opMul_09_D.d http://dstress.kuehne.cn/nocompile/o/opMul_09_E.d http://dstress.kuehne.cn/nocompile/o/opMul_09_F.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_A.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_B.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_C.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_D.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_E.d http://dstress.kuehne.cn/nocompile/o/opSubAssign_19_F.d http://dstress.kuehne.cn/nocompile/o/opSub_09_A.d http://dstress.kuehne.cn/nocompile/o/opSub_09_B.d http://dstress.kuehne.cn/nocompile/o/opSub_09_C.d http://dstress.kuehne.cn/nocompile/o/opSub_09_D.d http://dstress.kuehne.cn/nocompile/o/opSub_09_E.d http://dstress.kuehne.cn/nocompile/o/opSub_09_F.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFEBq+z3w+/yD4P9tIRAu3OAJ45EVLFHn6vpmX4YjKpmEGbpV80PQCeN+Ep sBYS2snC2tpi10blB5MXRHk= =mASe -----END PGP SIGNATURE-----
Mar 02 2006
prev sibling parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Don Clugston schrieb am 2006-02-28:

[snip]

 OK, there's another bug in there, comparing an int with an imaginary 
 real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats. # import std.stdio; # # int main(){ # creal a = 1; # creal b = 1i; # # writefln("a: %s", a); # writefln("b: %s", b); # # writefln("1 == 1i: %s", (1 == 1i) ? true : false); # writefln("1 == 0i: %s", (1 == 0i) ? true : false); # writefln("0 == 1i: %s", (1 == 0i) ? true : false); # writefln("0 == 0i: %s", (0 == 0i) ? true : false); # # return 0; # } Thus
      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }

The remaining question is: Is the second example unordered (due to the inan) or ordered? std.typeinfo.ti_creal._compare(creal, creal): ordered std.conv.feq(creal, creal): unordered http://www.digitalmars.com/d/float.html seems silent on this regard. Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFEBqMm3w+/yD4P9tIRAlwnAJ9wYssi82l6Ompor3gKx90+8rCEhQCgycyh m5cfl2rRa9afNi1dkdL1GeM= =6QJy -----END PGP SIGNATURE-----
Mar 02 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 Don Clugston schrieb am 2006-02-28:
 
 [snip]
 
 OK, there's another bug in there, comparing an int with an imaginary 
 real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats.

That only gives you == and !=. <snip>
 Thus
 
      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }


Yes, but that still doesn't work, there's no > for complex numbers. Is 2 - 3i > 3 - 2i ?
Mar 02 2006
parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Don Clugston wrote:
 Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Don Clugston schrieb am 2006-02-28:

 [snip]

 OK, there's another bug in there, comparing an int with an imaginary 
 real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats.

That only gives you == and !=. <snip>
 Thus

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }


Yes, but that still doesn't work, there's no > for complex numbers. Is 2 - 3i > 3 - 2i ?

One could speak of their magnitudes, I suppose. creal i = 2 - 3i; creal j = 3 - 2i; real i_m = sqrt(i * complexConjugate(i)); real j_m = sqrt(j * complexConjugate(j)); but then I guess you are just comparing reals.
Mar 02 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Kyle Furlong wrote:
 Don Clugston wrote:
 Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Don Clugston schrieb am 2006-02-28:

 [snip]

 OK, there's another bug in there, comparing an int with an imaginary 
 real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats.

That only gives you == and !=. <snip>
 Thus

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }


Yes, but that still doesn't work, there's no > for complex numbers. Is 2 - 3i > 3 - 2i ?

One could speak of their magnitudes, I suppose. creal i = 2 - 3i; creal j = 3 - 2i; real i_m = sqrt(i * complexConjugate(i)); real j_m = sqrt(j * complexConjugate(j)); but then I guess you are just comparing reals.

And then you have the problem (as in this case) that (i >= j) is true, and (i <= j) is true, but (i==j) is false. Actually, though, you _could_ bring the NCEG operators into play, and define a > b as abs(a) > abs(b) a >= b as abs(a) > abs(b) || a==b a !< b as abs(a) !< abs(b) a !<=b as abs(a) !< abs(b) && a!=b a <> b as abs(a) != abs(b) a !<>b as abs(a) == abs(b) a == b as a == b a <>=b as abs(a) <> abs(b) || a==b a!<>=b as abs(a) == abs(b) && a!=b which would even work correctly with NANs. But there's no mathematical precedent for this, AFAIK.
Mar 02 2006
parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Don Clugston wrote:
 Kyle Furlong wrote:
 Don Clugston wrote:
 Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Don Clugston schrieb am 2006-02-28:

 [snip]

 OK, there's another bug in there, comparing an int with an 
 imaginary real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats.

That only gives you == and !=. <snip>
 Thus

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }


Yes, but that still doesn't work, there's no > for complex numbers. Is 2 - 3i > 3 - 2i ?

One could speak of their magnitudes, I suppose. creal i = 2 - 3i; creal j = 3 - 2i; real i_m = sqrt(i * complexConjugate(i)); real j_m = sqrt(j * complexConjugate(j)); but then I guess you are just comparing reals.

And then you have the problem (as in this case) that (i >= j) is true, and (i <= j) is true, but (i==j) is false. Actually, though, you _could_ bring the NCEG operators into play, and define a > b as abs(a) > abs(b) a >= b as abs(a) > abs(b) || a==b a !< b as abs(a) !< abs(b) a !<=b as abs(a) !< abs(b) && a!=b a <> b as abs(a) != abs(b) a !<>b as abs(a) == abs(b) a == b as a == b a <>=b as abs(a) <> abs(b) || a==b a!<>=b as abs(a) == abs(b) && a!=b which would even work correctly with NANs. But there's no mathematical precedent for this, AFAIK.

As long as its well documented and doesn't introduce bugs, why not?
Mar 02 2006
next sibling parent Don Clugston <dac nospam.com.au> writes:
 Yes, but that still doesn't work, there's no > for complex numbers.
 Is  2 - 3i > 3 - 2i ?

One could speak of their magnitudes, I suppose. creal i = 2 - 3i; creal j = 3 - 2i; real i_m = sqrt(i * complexConjugate(i)); real j_m = sqrt(j * complexConjugate(j)); but then I guess you are just comparing reals.

And then you have the problem (as in this case) that (i >= j) is true, and (i <= j) is true, but (i==j) is false. Actually, though, you _could_ bring the NCEG operators into play, and define a > b as abs(a) > abs(b) a >= b as abs(a) > abs(b) || a==b a !< b as abs(a) !< abs(b) a !<=b as abs(a) !< abs(b) && a!=b a <> b as abs(a) != abs(b) a !<>b as abs(a) == abs(b) a == b as a == b a <>=b as abs(a) <> abs(b) || a==b a!<>=b as abs(a) == abs(b) && a!=b which would even work correctly with NANs. But there's no mathematical precedent for this, AFAIK.

As long as its well documented and doesn't introduce bugs, why not?

I really don't think it's a good idea (mathematicians would laugh at us). If you want to compare the magnitudes, you should say so. But, I find it interesting that the NCEG operators allow you to define meaningful ordering comparisons for quantities for which a strict weak ordering does not exist.
Mar 02 2006
prev sibling parent Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Kyle Furlong schrieb am 2006-03-03:
 Don Clugston wrote:
 Kyle Furlong wrote:
 Don Clugston wrote:
 Thomas Kuehne wrote:
 Don Clugston schrieb am 2006-02-28:

 [snip]

 OK, there's another bug in there, comparing an int with an 
 imaginary real should also not be legal.

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

 Reals and ireals cannot be compared. Ever.

Sure you can. Floats and imaginary floats can both be implicitly promoted to complex floats.

That only gives you == and !=. <snip>
 Thus

      if (1 > -2i) { assert(0); }
      if (1 > ireal.nan) { assert(0); }

are interpreted as
      if (1 + 0i > 0 - 2i) { ... }
      if (1 + 0i > 0 + ireal.nan) { ... }


Yes, but that still doesn't work, there's no > for complex numbers. Is 2 - 3i > 3 - 2i ?

One could speak of their magnitudes, I suppose. creal i = 2 - 3i; creal j = 3 - 2i; real i_m = sqrt(i * complexConjugate(i)); real j_m = sqrt(j * complexConjugate(j)); but then I guess you are just comparing reals.

And then you have the problem (as in this case) that (i >= j) is true, and (i <= j) is true, but (i==j) is false. Actually, though, you _could_ bring the NCEG operators into play, and define a > b as abs(a) > abs(b) a >= b as abs(a) > abs(b) || a==b a !< b as abs(a) !< abs(b) a !<=b as abs(a) !< abs(b) && a!=b a <> b as abs(a) != abs(b) a !<>b as abs(a) == abs(b) a == b as a == b a <>=b as abs(a) <> abs(b) || a==b a!<>=b as abs(a) == abs(b) && a!=b which would even work correctly with NANs. But there's no mathematical precedent for this, AFAIK.

As long as its well documented and doesn't introduce bugs, why not?

http://www.digitalmars.com/d/float.html # Floating Point Comparisons # # In addition to the usual < <= > >= == != comparison operators, D adds # more that are specific to floating point. These are !<>= <> <>= !<= !< # !>= !> !<> and match the semantics for the NCEG extensions to C. creal/cdouble/cfloat are "Floating Point Types" and "Floating Point Comparisons" are those stated by NCEG. So what does NCEG say on compairing _Complex? (Couldn't find any useful NCEG documents ...) Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFECHri3w+/yD4P9tIRApwuAJ46SuFsHnytm8aVfp4/w9fnt7Le4gCfSb6F Zu/XOm3qGyAJ14TyVUKQBv4= =WDhO -----END PGP SIGNATURE-----
Mar 03 2006
prev sibling parent Kyle Furlong <kylefurlong gmail.com> writes:
Don Clugston wrote:
 Four examples, although it's only one bug. Almost all operations on bool 
 should be disabled, but I found the ones below a little amusing. None of 
 them should compile, but they all evaluate as "true".
 
 void main()
 {
     if (true >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (false >= ireal.nan) { writefln("This is kind of ridiculous"); }
     if (true <> -2i) { writefln("NCEG operators too ??!!"); }
     if (false != -2i) { writefln("and again"); }
 }

This kind of absurdity is exactly what Derek and others of us have been arguing against. These are a direct result of a non type safe boolean.
Feb 28 2006