On Wed, 26 Nov 2008 18:24:17 +0300, Andrei Alexandrescu <[EMAIL PROTECTED]> 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.

Reply via email to