On Friday, 26 May 2017 at 09:59:26 UTC, zakk wrote:

My questions are:

1) Why is D making using of the binary ! operator, which as far as I understand introduces a template?

The ! operator *instantiates* a template. Whenever you need to specify compile-time arguments to match the template parameters, you need to use !. Templated functions are implemented like this:

template myTemplateFunc(<Template parameters go here>) {
    void myTemplateFunc(<Function parameters go here>) {
        ....
    }
}

Template parameters are used at compile time, usually to generate the code for the function, and function parameters are used at runtime. When the template and the function have the same name, you can shorten the declaration like so:

void myTemplateFunc(<Template parameters>)(<Function parameters>);

With many templated functions, the template parameters can be inferred by the compiler from the function parameters:

void myFunc(T)(T arg) {...}

In this case, you can call myFunc using the instantiation operator:

myFunc!(int)(10);

Or, since the compiler has enough information to infer T (10 is an int, arg is a T, therefore T is int), you can call it like a normal function:

myFunc(10);

Template parameters can be given default values, just like function parameters. If all of the template parameters have default values or can be inferred, the ! can be omitted in the function call.

If you look at the documentation for sort [1], you'll see it's declared to take three template arguments. The first two are given default values. The last one is not, but since it is the type of the function parameter, it can be inferred and not specified. So sort *can* be called like this:

sort(myList);

And this will use the default comparison function, the default SwapStrategy, and the type of myList will be inferred. If you want to change the default comparison function or SwapStrategy, you need to use the instantiation operator to specify them. That's why it's needed in your example.



2) Why is a template needed here?

It's not that a template is needed, but that sort is implemented as a templated function. I think my answer to number 1 should clear this one up, too.



3) It seems to me like the argument passed to the template is a lambda expression. I only know about templates taking types as argument. What's going on?

There are a few different kinds of template parameters [2]. Types are perhaps the most common, but there are also template value parameters (any compile-time constant), template alias parameters (which can be any symbol or compile-time constant), and more. In the declaration of sort, you can see three kinds in action:

SortedRange!(Range, less)
sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)

The first template parameter, less, is an alias parameter. The default value is a string literal which can be mixed in. But you could also pass a function name, a function literal (lambda), or even an object with a compatible opCall implementation (assuming the symbol is in the template's scope). The second parameter is a value parameter. SwapStrategy is an enum, the values of which are known at compile time. Finally, Range is a type. We know this because there's no "alias" or type name in front of it -- it's just a solitary symbol.

[1] http://dlang.org/phobos/std_algorithm_sorting.html#sort
[2] http://dlang.org/spec/template.html

Reply via email to