digitalmars.D - is this intended behavior?
- Frank Malone (9/9) Apr 09 2007 dmd v1.010
- unknown (4/8) Apr 09 2007 Please read the documentation or post to the learn forum. thx.
- John Demme (8/19) Apr 09 2007 In all fairness, DMD should catch it at compile time and throw an error....
- Derek Parnell (9/19) Apr 09 2007 Yes, kind of ... it is undefined behaviour ... the compiler doesn't know
- Don Clugston (11/27) Apr 10 2007 I agree.
- James Dennett (14/43) Apr 10 2007 It's a shame if a language can't make the code above
- Don Clugston (8/50) Apr 11 2007 I don't think that's necessarily true. -3 < (uint)x is quite likely to
- James Dennett (9/57) Apr 11 2007 Except in generic code, where the uint is likely to
- James Dennett (15/64) Apr 11 2007 Or the more common case: the function has an int and
- Don Clugston (16/70) Apr 12 2007 I think there's it is still likely to be a logical error, even in that
- Serg Kovrov (4/8) Apr 18 2007 My thoughts, exactly.
- Dan (3/4) Apr 10 2007 I totally agree with Walter's reason for not using "warnings". Indeed, ...
dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }
Apr 09 2007
Frank Malone Wrote:writefln(c < a ? "true" : "false"); // outputs falseFrom the documentation:It is an error to have one operand be signed and the other unsigned for a <, <=, > or >= expression. Use casts to make both operands signed or both operands unsigned.Please read the documentation or post to the learn forum. thx. unknown []
Apr 09 2007
unknown wrote:Frank Malone Wrote:In all fairness, DMD should catch it at compile time and throw an error. It doesn't even spit out a warning. I'd consider this a bug- the code shouldn't compile, or at least a warning should be issued. -- ~John Demme me teqdruid.com http://www.teqdruid.com/writefln(c < a ? "true" : "false"); // outputs falseFrom the documentation:It is an error to have one operand be signed and the other unsigned for a <, <=, > or >= expression. Use casts to make both operands signed or both operands unsigned.Please read the documentation or post to the learn forum. thx. unknown []
Apr 09 2007
John Demme wrote:unknown wrote:Couldn't agree more. I've tripped on this exact issue a few times and seen numerous other people suffer from it. -- Tomasz StachowiakFrank Malone Wrote:In all fairness, DMD should catch it at compile time and throw an error. It doesn't even spit out a warning. I'd consider this a bug- the code shouldn't compile, or at least a warning should be issued.writefln(c < a ? "true" : "false"); // outputs falseFrom the documentation:It is an error to have one operand be signed and the other unsigned for a <, <=, > or >= expression. Use casts to make both operands signed or both operands unsigned.Please read the documentation or post to the learn forum. thx. unknown []
Apr 09 2007
Tom S Wrote:John Demme wrote:What it appears to be doing incorrectly is attempting to convert -1 to an unsigned value to compute the comparison; which should produce uint.max; while the ubyte may be converting to a uint as well. (int < ubyte) ought to be reasonable to use. The fact it isn't never occurred to me, and would demonstrate that the language is still lacking in a couple quite fundamental areas.unknown wrote:Frank Malone Wrote:writefln(c < a ? "true" : "false"); // outputs false
Apr 09 2007
Dan wrote:Tom S Wrote:language is still lacking in a couple quite fundamental areas. What makes this a big WTF, is that the conversion from int to uint is done on the opposite side of the comparison as the conversion from ubyte to int. It's almost as if the compiler tries to implicitly convert the right-hand side, fails, then attempts to implicitly convert the left, and passes. IMO, behavior that complicated (and subtle!) should be defined, and documented if not labeled a bug. Either that, or it should force a cast() in cases where mixed types can yield unpredictable results. -- - EricAnderton at yahooJohn Demme wrote:What it appears to be doing incorrectly is attempting to convert -1 to an unsigned value to compute the comparison; which should produce uint.max; while the ubyte may be converting to a uint as well. (int < ubyte) ought to be reasonable to use. The fact it isn't never occurred to me, and would demonstrate that theunknown wrote:Frank Malone Wrote:writefln(c < a ? "true" : "false"); // outputs false
Apr 10 2007
On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Apr 09 2007
Derek Parnell wrote:On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.
Apr 10 2007
Don Clugston wrote:Derek Parnell wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type. With an int a and a uint b, "a<b" should give the same result as "(a<0) || ((uint)a < b)" -- where the conversion happens only in cases where it fits. In general, if the value of one side of the comparison is out of range for the other side, the answer is known without testing the other value. Concretely, for example, -3 < (uint)x for all x, and similarly 257 > (ubyte)y for all y. -- JamesOn Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.
Apr 10 2007
James Dennett wrote:Don Clugston wrote:I don't think that's necessarily true. -3 < (uint)x is quite likely to be a bug. I would want an error message if I ever wrote that -- it doesn't make sense. OTOH (uint)x > 3 makes perfect sense, as does (int)x>3. The underlying problem is that uint doesn't necessarily mean "positive integer", it just means "no sign bit"; it could be the low part of a multi-byte integer, for example. Whereas a positive literal in the range 0..int.max has no such ambiguity.Derek Parnell wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type. With an int a and a uint b, "a<b" should give the same result as "(a<0) || ((uint)a < b)" -- where the conversion happens only in cases where it fits. In general, if the value of one side of the comparison is out of range for the other side, the answer is known without testing the other value. Concretely, for example, -3 < (uint)x for all x, and similarly 257 > (ubyte)y for all y.On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.
Apr 11 2007
Don Clugston wrote:James Dennett wrote:Except in generic code, where the uint is likely to depend on a type parameter.Don Clugston wrote:I don't think that's necessarily true. -3 < (uint)x is quite likely to be a bug.Derek Parnell wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type. With an int a and a uint b, "a<b" should give the same result as "(a<0) || ((uint)a < b)" -- where the conversion happens only in cases where it fits. In general, if the value of one side of the comparison is out of range for the other side, the answer is known without testing the other value. Concretely, for example, -3 < (uint)x for all x, and similarly 257 > (ubyte)y for all y.On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.I would want an error message if I ever wrote that -- it doesn't make sense.In a language with generics, it makes sense. (Even in a language with code generation facilities, it makes sense; however code might arise that does not know up front which types it might be used with, the rule I suggest makes code work smoothly across all types.) -- James
Apr 11 2007
James Dennett wrote:Don Clugston wrote:Or the more common case: the function has an int and a uint as variables that it wishes to compare. (Sorry, I didn't imagine people would think this was intended for literal values, when I was writing about how comparisons between types should work.) It's perfectly reasonable to compare unknown values of two different integral types. It's *unreasonable* for such a conversion to compile and then not follow the rules I give, because it will lead to bugs. It's been tried (C, C++) and the consequences are fairly well known -- bugs, compiler warnings to try to avoid the bugs, casts to try to avoid the compiler warnings but without fixing the bugs, and so on. -- JamesJames Dennett wrote:Except in generic code, where the uint is likely to depend on a type parameter.Don Clugston wrote:I don't think that's necessarily true. -3 < (uint)x is quite likely to be a bug.Derek Parnell wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type. With an int a and a uint b, "a<b" should give the same result as "(a<0) || ((uint)a < b)" -- where the conversion happens only in cases where it fits. In general, if the value of one side of the comparison is out of range for the other side, the answer is known without testing the other value. Concretely, for example, -3 < (uint)x for all x, and similarly 257 > (ubyte)y for all y.On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.
Apr 11 2007
James Dennett wrote:James Dennett wrote:I think there's it is still likely to be a logical error, even in that situation.Don Clugston wrote:James Dennett wrote:Except in generic code, where the uint is likely to depend on a type parameter.Don Clugston wrote:I don't think that's necessarily true. -3 < (uint)x is quite likely to be a bug.Derek Parnell wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type. With an int a and a uint b, "a<b" should give the same result as "(a<0) || ((uint)a < b)" -- where the conversion happens only in cases where it fits. In general, if the value of one side of the comparison is out of range for the other side, the answer is known without testing the other value. Concretely, for example, -3 < (uint)x for all x, and similarly 257 > (ubyte)y for all y.On Mon, 09 Apr 2007 15:01:56 -0400, Frank Malone wrote:I agree. I think we should seriously consider the possibility that literals should be treated differently to variables, as regards signed-unsigned mismatches. * If the value fits in the range 0..int.max, it should be implicitly convertible to int, or to uint. --> 100% guaranteed safe. * If it is outside that range, an error should be issued, since it is definitely a bug. My feeling is, that this would eliminate most of the annoying & useless signed/unsigned mismatch warnings, and catch many of the real bugs.dmd v1.010 import std.stdio; void main() { uint a = 3; ubyte b = 3; int c = -1; writefln(c < a ? "true" : "false"); // outputs false writefln(c < b ? "true" : "false"); // outputs true }Yes, kind of ... it is undefined behaviour ... the compiler doesn't know what to do so it does something dumb instead. I believe that a warning (a.k.a "error" in Walter-speak) should be issued by the compiler.Or the more common case: the function has an int and a uint as variables that it wishes to compare. (Sorry, I didn't imagine people would think this was intended for literal values, when I was writing about how comparisons between types should work.)Ah, OK. I might agree with you when both are variables. But I strongly believe that comparing an unsigned variable with a negative literal shouldn't be optimised away, it should be an error. Although I think that comparing two variables which differ in both size AND signedness is very suspicious behaviour. Eg uint a; byte b; if (a<b) ... Suppose a=250. Intention is catch all values in the range 250-255. But the coder has forgotten that 'byte' is a signed type; b should have been a ubyte. (And in the case where a is a constant, this bug is actually *likely*).
Apr 12 2007
James Dennett wrote:It's a shame if a language can't make the code above do the right thing, and the right thing is simple: -1 is less than 3, report that. Don't try to make comparisons convert their arguments to a common type.My thoughts, exactly. -- serg.
Apr 18 2007
Derek Parnell Wrote:(a.k.a "error" in Walter-speak) should be issued by the compiler.I totally agree with Walter's reason for not using "warnings". Indeed, the program should either be correct, and compile and run successfully, or incorrect and not compile or run at all. In this way, we know whether or not we have to fix something, and we don't get bombarded by stupid messages that some people tend to ignore.
Apr 10 2007