| |
| Posted by Andrei Alexandrescu | PermalinkReply |
|
Andrei Alexandrescu
| 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`.
|