Why is mostNegative!T not of type T?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sun Oct 17 19:32:16 UTC 2021


https://github.com/dlang/phobos/blob/master/std/traits.d#L8217


template mostNegative(T)
if (isNumeric!T || isSomeChar!T || isBoolean!T)
{
     static if (is(typeof(T.min_normal)))
         enum mostNegative = -T.max;
     else static if (T.min == 0)
         enum byte mostNegative = 0;
     else
         enum mostNegative = T.min;
}

This is a breakage of the Rule of Least Astonishment: mostNegative!T for 
all unsigned types yields type byte.

I tried to simplify as follows:

template mostNegative(T)
if (isNumeric!T || isSomeChar!T || isBoolean!T)
{
     static if (is(typeof(T.min_normal)))
         enum mostNegative = -T.max;
     else
         enum mostNegative = T.min;
}

Got errors all the way over in unittests of 
std.algorithm.comparison.clamp. Looking at the definition of clamp:

auto clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
if (is(typeof(max(min(val, upper), lower))))
in
{
     import std.functional : greaterThan;
     assert(!lower.greaterThan(upper), "Lower can't be greater than 
upper.");
}
do
{
     return max(min(val, upper), lower);
}

In turn, min and max use mostNegative and makes surprising deductions 
based on its type. The surprise has been deemed desirable and has become 
part of an unnecessarily complex mesh.

The failing unittest is:

     int a = -5;
     uint f = 5;
     short b = 6;
     static assert(is(typeof(clamp(f, a, b)) == int));

This is bizarre and very arguably a bug, as one would expect clamping a 
value of type `whatever` would yield a value of type `whatever`.



More information about the Digitalmars-d mailing list