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