Rant after trying Rust a bit

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Sat Jul 25 02:14:02 PDT 2015


On Saturday, 25 July 2015 at 08:48:40 UTC, Walter Bright wrote:
> On 7/24/2015 11:10 PM, Jonathan M Davis wrote:
>> So, maybe we should look at something along those lines rather 
>> than
>> proliferating the top-level function overloading like we're 
>> doing now.
>
> Consider the following pattern, which I see often in Phobos:
>
>     void foo(T)(T t) if (A) { ... }
>     void foo(T)(T t) if (!A && B) { ... }
>
> from a documentation (i.e. user) perspective. Now consider:
>
>     void foo(T)(T t) if (A || B)
>     {
>          static if (A) { ... }
>          else static if (B) { ... }
>          else static assert(0);
>     }
>
> Makes a lot more sense to the user, who just sees one function 
> that needs A or B, and doesn't see the internal logic.

Yeah, though, I believe that Andrei has argued against that every 
time that someone suggests doing that. IIRC, he wants ddoc to 
that for you somehow rather than requiring that we write code 
that way.

And from a test perspective, it's actually a bit ugly to take 
function overloads and turn them into static ifs, because instead 
of having separate functions that you can put unittest blocks 
under, you have to put all of those tests in a single unittest 
block or put the unittest blocks in a row with comments on them 
to indicate which static if branch they go with. It also has the 
problem that the function can get _way_ too long (e.g. putting 
all of the overloads of find in one function would be a really 
bad idea).

Alternatively, you could do something like

template foo(T)
     if(A || B)
{
     void foo()(T t)
         if(A)
     {}

     void foo()(T t)
         if(B)
     {}
}

which gives you the simplified template constraint for the 
documentation, though for better or worse, you'd still get the 
individual template constraints listed separately for each 
overload - though given how often each overload needs an 
explanation, that's not necessarily bad.

And in many cases, what you really have is overlapping 
constraints rather than truly distinct ones. So, you'd have 
something like

auto foo(alias pred, R)(R r)
     if(testPred!pred && isInputRange!R && !isForwardRange!R)
{}

auto foo(alias pred, R)(R r)
     if(testPred!pred && isForwardRange!R)
{}

and be turning it into something like

template foo(alias pred)
     if(testPred!pred)
{
     auto foo(R)(R r)
         if(isInputRange!R && !isForwardRange!R)
     {}

     auto foo(R)(R r)
         if(isForwardRange!R)
     {}
}

So, part of the template constraint gets factored out completely. 
And if you want to factor it out more than that but still don't 
want to use static if because of how it affects the unit tests, 
or because you don't want the function to get overly large, then 
you can just forward it to another function. e.g.

auto foo(alias pred, R)(R r)
     if(testPred!pred && isInputRange!R)
{
     return _foo(pred, r);
}

auto _foo(alias pred, R)(R r)
     if(!isForwardRange!R)
{}

auto _foo(alias pred, R)(R r)
     if(isForwardRange!R)
{}

or go for both the outer template and forwarding, and do

template foo(alias pred)
     if(testPred!pred)
{
     auto foo(R)(R r)
         if(isInputRange!R)
     {
         return _foo(pred, r);
     }

     auto _foo(R)(R r)
         if(!isForwardRange!R)
     {}

     auto _foo(R)(R r)
         if(isForwardRange!R)
     {}
}

We've already created wrapper templates for at least some of the 
functions in Phobos so that you can partially instantiate them - 
e.g.

alias myMap = map!(a => a.func());

So, it we're already partially moving stuff up a level in some 
cases. We just haven't used it as a method to simplify the main 
template constraint that user sees or to simplify overloads.

I do think that it can make sense to put very similar overloads 
in a single function with static if branches like you're 
suggesting, but I do think that it's a bit of a maintenance issue 
to do it for completely distinct overloads - especially if there 
are several of them rather than just a couple. But it's still 
possible to combine their template constraints at a higher level 
and have overloaded functions rather than simply using static ifs.

- Jonathan M Davis


More information about the Digitalmars-d mailing list