Treating the abusive unsigned syndrome
Denis Koroskin
2korden at gmail.com
Wed Nov 26 09:50:52 PST 2008
On Wed, 26 Nov 2008 18:24:17 +0300, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:
> Also consider:
>
> auto delta = a1.length - a2.length;
>
> What should the type of delta be? Well, it depends. In my scheme that
> wouldn't even compile, which I think is a good thing; you must decide
> whether prior information makes it an unsigned or a signed integral.
>
Sure, it shouldn't compile. But explicit casting to either type won't
help. Let's say you expect that a1.length > a2.length and thus expect a
strictly positive result. Putting an explicit cast will not detect (but
suppress) an error and give you an erroneous result silently.
Putting an assert(a1.length > a2.length) might help, but the check will be
unavailable unless code is compiled with asserts enabled.
A better solution would be to write code as follows:
auto delta = unsigned(a1.length - a2.length); // returns an unsigned
value, throws on overflow (i.e., "2 - 4")
auto delta = signed(a1.length - a2.length); // returns result as a signed
value. Throws on overflow (i.e., "int.min - 1")
auto delta = a1.length - a2.length; // won't compile
// this one is also handy:
auto newLength = checked(a1.length - 1); // preserves type of a1.length,
be it int or uint, throws on overflow
I have previously shown an implementation of unsigned/signed:
import std.stdio;
int signed(lazy int dg)
{
auto result = dg();
asm {
jo overflow;
}
return result;
overflow:
throw new Exception("Integer overflow occured");
}
int main()
{
int t = int.max;
try
{
int s = signed(t + 1);
writefln("Result is %d", s);
}
catch(Exception e)
{
writefln("Whoops! %s", e.toString());
}
return 0;
}
But Andrei has correctly pointed out that it has a problem - it may throw
without a reason:
int i = int.max + 1; // sets an overflow flag
auto result = expectSigned(1); // raises an exception
Overflow flag may also be cleared in a complex expression:
auto result = expectUnsigned(1 + (uint.max + 1)); // first add will
overflow and second one clears the flag -> no exception as a result
A possible solution is to make the compiler aware of this construct and
disallow passing none (case 2) or more that one operation (case 1) to the
method.
More information about the Digitalmars-d
mailing list