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