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

- Don Clugston <dac nospam.com.au> Feb 28 2006
- Oskar Linde <oskar.lindeREM OVEgmail.com> Feb 28 2006
- Don Clugston <dac nospam.com.au> Feb 28 2006
- Oskar Linde <oskar.lindeREM OVEgmail.com> Feb 28 2006
- Don Clugston <dac nospam.com.au> Mar 01 2006
- Thomas Kuehne <thomas-dloop kuehne.cn> Mar 02 2006
- Thomas Kuehne <thomas-dloop kuehne.cn> Mar 02 2006
- Don Clugston <dac nospam.com.au> Mar 02 2006
- Kyle Furlong <kylefurlong gmail.com> Mar 02 2006
- Don Clugston <dac nospam.com.au> Mar 02 2006
- Kyle Furlong <kylefurlong gmail.com> Mar 02 2006
- Don Clugston <dac nospam.com.au> Mar 02 2006
- Thomas Kuehne <thomas-dloop kuehne.cn> Mar 03 2006
- Kyle Furlong <kylefurlong gmail.com> Feb 28 2006

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

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

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

Don Clugston skrev:Oskar Linde wrote:Don Clugston skrev:

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

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

-----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

-----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; # } Thusif (1 > -2i) { assert(0); } if (1 > ireal.nan) { assert(0); }

are interpreted asif (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

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>Thusif (1 > -2i) { assert(0); } if (1 > ireal.nan) { assert(0); }

are interpreted asif (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

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>Thusif (1 > -2i) { assert(0); } if (1 > ireal.nan) { assert(0); }

are interpreted asif (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

Kyle Furlong wrote:Don Clugston wrote:Thomas Kuehne wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Don Clugston schrieb am 2006-02-28: [snip]

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

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

are interpreted asif (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

Don Clugston wrote:Kyle Furlong wrote:Don Clugston wrote:

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

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

are interpreted asif (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

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

-----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]

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

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

are interpreted asif (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

Don Clugston wrote:

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