On Sunday, 10 March 2013 at 02:35:28 UTC, Walter Bright wrote:
On 3/9/2013 8:22 AM, monarch_dodra wrote:
Things can get evenmore hairy,when you are operating on 2 different types.

This is why complex expressions can be encapsulated as functions.

Yes, but that doesn't solve the "root" issue of meaningfulness. Sure, instead of having a 5 line constraint, it's only a single line, but are these any better?

sort(R, Scheme)(...)
if(isRandomAccessRangeWithComparableElementsAndAssignableElementsIfStableSchemeOrSwapableElementsOtherwise!R)

or

sort(...)
    if(meetsSortConstraints!R)

Neither are really any better for the end user.

This is why I don't think constraints should be used at all for validating arguments. [concepts|static asserts] are much better, and when combined with static if, become incredibly powerful:

sort(R, Scheme)(...)
{
    static assert (isRandomAccessRange!T);
    static assert (is(typeof(r.front < r.front)));
    static if (Scheme == Stable)
        static assert (hasAssignableElements!T);
    else
        static assert (hasSwapableElements!T);

    //Code Code Code
}

Much clearer, and the diagnostics much better.

That said, we can also look for a "middle ground" where the constraints validate the broad requirements (RA, comparable), and the asserts validate the more complex stuff.

One last thing to keep in mind is that having constraints allows hijacking,
whereas concpets/static asserts resolve as an ambigus call.

I don't see where the hijacking comes in.

The problem with contraints is that it merelly eliminates functions from the pool of overloads. If you attemp to call a function with invalid parameters, then you may end up accidentally calling something you didn't want to. Imagine:

//----
module a;
void do_it(R)(R r)
    if (isForwardRange!R)
{
    //Do something to r
}
//----
module b;
void do_it(T)(T t)
{
    //Do something completely different
}
//----
import a, b;

void main()
{
MyInputRange myInputRange; //Oops! I didn't realize it's only input:
    do_it(myInputRange); //meant to call a.do_it;
}
//----

With the current scheme of constraints, this will end up calling b.do_it, without any ambiguity. You may or may not consider that is "hijacking", but it is error prone.

NOW, if we had defined a.do_it with concepts/static asserts, the programmer would have been served with a "ambiguous call: a.do_it or b.do_it"? So the coder would have to be "alright, I want to explicitly call a.do_it". To which this time the compiler replies "Error: isForwardRange!MyInputRange is false". To which the programmer replies "I understand my error and see what I did wrong".

--------------------------------------

I'm not saying template constraints are bad or anything, I think they are incredible tools for dispatching to specialized overloads.

However, In regards to *validating* the input, I think concepts/static asserts, are both more robust implementation-wise, while being clearer for the end coder.

Reply via email to