The core.checkedint module isn't meant to be used directly like this, it has the bricks to build partially library-defined safe integral types:

void main(in string[] args) {
    import std.stdio, std.conv, core.checkedint;

    assert(args.length == 3);
    immutable xy = args[1 .. $].to!(int[2]);

    bool overflow = false;
    immutable result = muls(xy[0], xy[1], overflow);
    assert(!overflow);
    writeln("Product: ", result);
}


Calls to core.checkedint functions are eventually meant to be replaced by faster compiler intrisics in all D compiler, that use the carry and overflow bits present in most CPUs.

But to be more useful, the compiler should replace safe integral operations with regular (faster) integral operations where it statically knows they can't overflow/underflow. In D there is value range propagation (that probably will be improved in future) that can be used for this. If the compiler replaces the calls to core.checkedint functions with intrinsics, it can also replace some calls with regular operations where it sees the value range makes an overflow impossible. This is a naive example:


void main() {
    import std.stdio, core.checkedint;
        
        ubyte x = 100;
        ubyte y = 200;  

    bool overflow = false;
    immutable result = muls(x, y, overflow);
    assert(!overflow);
    writeln("Product: ", result);
}


With a library-defined type the first program could look:


void main(in string[] args) {
    import std.stdio, std.conv, std.safeintegral;

    assert(args.length == 3);
    SInt x = args[1].to!int;
    SInt y = args[2].to!int;

    immutable result = x * y;
    assert(!result.overflow);
    writeln("Product: ", result);
}


where the operator "*" of SInt calls muls().


But while operations with ubyte and int values are able to use the range of values (to avoid casts), a library-defined type like SInt that calls muls() currently loses the knowledge of the range of the operands. How do you solve this problem? If you solve this problem for SInt, you can solve it for lot of other library-defined types.

A possible piece of the solution is the recently suggested __trait(valueRange, exp), but alone that's not enough.

Bye,
bearophile

Reply via email to