www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - is this intended behavior?

reply Frank Malone <fmalone gmial.com> writes:
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
next sibling parent reply unknown <unknown brackets.com> writes:
Frank Malone Wrote:
         writefln(c < a ? "true" : "false"); // outputs false

From 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
parent reply John Demme <me teqdruid.com> writes:
unknown wrote:

 Frank Malone Wrote:
         writefln(c < a ? "true" : "false"); // outputs false

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

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/
Apr 09 2007
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
John Demme wrote:
 unknown wrote:
 
 Frank Malone Wrote:
         writefln(c < a ? "true" : "false"); // outputs false

 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.

unknown []

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.

Couldn't agree more. I've tripped on this exact issue a few times and seen numerous other people suffer from it. -- Tomasz Stachowiak
Apr 09 2007
parent reply Dan <murpsoft hotmail.com> writes:
Tom S Wrote:

 John Demme wrote:
 unknown wrote:
 
 Frank Malone Wrote:
         writefln(c < a ? "true" : "false"); // outputs false




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.
Apr 09 2007
parent Pragma <ericanderton yahoo.removeme.com> writes:
Dan wrote:
 Tom S Wrote:
 
 John Demme wrote:
 unknown wrote:

 Frank Malone Wrote:
         writefln(c < a ? "true" : "false"); // outputs false




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

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 yahoo
Apr 10 2007
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
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
parent reply Don Clugston <dac nospam.com.au> writes:
Derek Parnell wrote:
 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.

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.
Apr 10 2007
parent reply James Dennett <jdennett acm.org> writes:
Don Clugston wrote:
 Derek Parnell wrote:
 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.

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.

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. -- James
Apr 10 2007
next sibling parent reply Don Clugston <dac nospam.com.au> writes:
James Dennett wrote:
 Don Clugston wrote:
 Derek Parnell wrote:
 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
 }

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

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.

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.
Apr 11 2007
parent reply James Dennett <jdennett acm.org> writes:
Don Clugston wrote:
 James Dennett wrote:
 Don Clugston wrote:
 Derek Parnell wrote:
 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
 }

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

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.

be a bug.

Except in generic code, where the uint is likely to depend on a type parameter.
 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
parent reply James Dennett <jdennett acm.org> writes:
James Dennett wrote:
 Don Clugston wrote:
 James Dennett wrote:
 Don Clugston wrote:
 Derek Parnell wrote:
 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
 }

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

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.

be a bug.

Except in generic code, where the uint is likely to depend on a type parameter.

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. -- James
Apr 11 2007
parent Don Clugston <dac nospam.com.au> writes:
James Dennett wrote:
 James Dennett wrote:
 Don Clugston wrote:
 James Dennett wrote:
 Don Clugston wrote:
 Derek Parnell wrote:
 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
 }

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

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.

be a bug.

depend on a type parameter.


I think there's it is still likely to be a logical error, even in that situation.
 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
prev sibling parent Serg Kovrov <kovrov no.spam> writes:
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