A Huge Bummer When Using alias this

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Thu Mar 24 20:30:52 PDT 2016


On Thursday, March 24, 2016 21:26:00 Jack Stouffer via Digitalmars-d wrote:
> alias this is only useful when not using any function that relies
> on the template constraints in std.traits.
>
> For example
>
> import std.traits;
>
> void someFunc(N)(N val) if (isNumeric!N)
> {
>      int b = val;
> }
>
> void main()
> {
>      import std.typecons;
>      Nullable!int a = 42;
>
>      someFunc(a);
> }
>
> $ dmd test.d
> test.d(13): Error: template someFunc cannot deduce function from
> argument types !()(Nullable!(int))
>
> Removing the template constraint makes it compile and run just
> fine. What's a good work around for these types of issues?

In general, using alias this with templates is a recipe for disaster. It's
downright trivial to write a template constraint that works thanks to
implicit conversion and end up with a function that doesn't compile, because
it never explicitly converts the type. As a result, the traits in std.traits
specifically do _not_ operate on implicitly convertible types - only on the
exact type. It avoids a whole mess of pain.

Any templated functions that _want_ to accept implicit conversions, need to
be explicitly written with that in mind, and they need to make sure that
they explicitly convert the given variable to the target type and not leave
it as whatever type it is, because if the conversion is not forced, then
it's unlikely to happen, and you'll get compilation errors - or worse,
weird, unexpected behaviors that do compile but do the wrong thing.

So, if you want to use an implicit conversion, traits like isNumeric are not
what you want at all. You want to check that the type converts to exactly
what you want it to convert to. In this case, assigning it to an int, so
that's what you want to test. e.g.

    void someFunc(N)(N val)
        if(is(T : int))
    {
        int b = val;
    }

And note that with your example, using isNumeric!N is completely wrong in
the first place, because while int is numeric, not all numeric types -
built-in or otherwise - will implicitly convert to int. For instance, with
your example someFunc(long.max) will pass the template constraint but fail
to compile. So, even if isNumeric worked with implicit conversions, using it
for someFunc would still be wrong.

But the bottom line is that if you want to use an implicit conversion, then
test for that conversion explicitly and then do the conversion explicitly
within the function. Don't write a template constraint where implicit
conversion to a range of types is allowed - make it one type explicitly -
and don't write a template constraint that allows implicit conversions but
doesn't actually force the conversion. If you don't follow those rules, then
at best, you're going to end up with code that works with some types and not
others, and at worst, you could get some nasty, subtle bugs when conversions
happen in only part of the function.

- Jonathan M Davis



More information about the Digitalmars-d mailing list