April 12, 2007 Re: is this intended behavior? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 >>>>> } >>>> 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. > I don't think that's necessarily true. -3 < (uint)x is quite likely to > 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 |
April 12, 2007 Re: is this intended behavior? | ||||
---|---|---|---|---|
| ||||
Posted in reply to James Dennett | 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
>>>>>> }
>>>>> 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.
>> I don't think that's necessarily true. -3 < (uint)x is quite likely to
>> 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
|
April 13, 2007 Re: is this intended behavior? | ||||
---|---|---|---|---|
| ||||
Posted in reply to James Dennett | 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 >>>>>>> } >>>>>> 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. >>> I don't think that's necessarily true. -3 < (uint)x is quite likely to >>> be a bug. >> Except in generic code, where the uint is likely to >> 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*). |
April 18, 2007 Re: is this intended behavior? | ||||
---|---|---|---|---|
| ||||
Posted in reply to James Dennett | 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. |
Copyright © 1999-2021 by the D Language Foundation