On Thursday, 5 December 2013 at 17:44:18 UTC, H. S. Teoh wrote:
On Thu, Dec 05, 2013 at 06:15:37PM +0100, Steve Teale wrote:
Here I feel like a beginner, but it seems very unfriendly:

import std.stdio;

struct ABC
{
   double a;
   int b;
   bool c;
}

ABC[20] aabc;

void foo(int n)
{
   writefln("n: %d, aabc.length: %d", n, aabc.length);
   if (n < aabc.length)
      writeln("A");
   else
      writeln("B");
}

void main(string[] args)
{
   int n = -1;
   foo(n);
}

This comes back with "B".

If I change the test to (n < cast(int) aabc.length), then all is
well.

Is this unavoidable, or could the compiler safely make the
conversion implicitly?

Comparing a signed value to an unsigned value is a risky operation. You should always compare values of like signedness, otherwise you'll run
into problems like this.

You can't compare -1 to an unsigned value because if that unsigned value happens to be uint.max, then there is no machine instruction that will give the correct result (the compiler would have to substitute the code
with something like:

        uint y;
        if (x < 0 || cast(uint)x < y) { ... }

which will probably introduce undesirable overhead.

The compiler also can't automatically convert aabc.length to int,
because if the length is greater than int.max (which is half of
uint.max), the conversion would produce a wrong negative value instead,
and the comparison will fail.

So, comparing a signed value to an unsigned value is a dangerous,
error-prone operation.  Sadly, dmd doesn't warn about such risky
operations; it just silently casts the values. Bearophile has often
complained about this, and I'm starting to agree. This is one

me too, me too, me too

Reply via email to