www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Practical difference between template "alias" arguments/normal generic

reply Juanjo Alvarez <gorthol protonmail.com> writes:
Hi!

With "alias this" accepting runtime variables I'm struggling to 
understand the difference between a generic function with an 
"alias this" parameter and another one with a "runtime" parameter 
of template type.

Example:

// ---- example code ----
import std.stdio: writeln;

void writevalue1(alias param)() { writeln(param); }

void writevalue2(T)(T param) { writeln(param); }

void main() {
   import std.random: uniform;
   auto someNum = uniform(0, 1000); // runtime value
   writevalue1(someNum);
   someNum = uniform(0, 1000);
   writevalue2(someNum);
}
// ---- example end -----

Since both versions work with runtime values, what's are the 
differences? When I should prefer one version over the other?

If objdump is not lying to me, both calls jump to the same 
assembly and the only diffence is that the call to writevalue1 
does a "mov -0x8(%rdi),%edi" just before the callq instruction.
Apr 12
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 12 April 2017 at 11:06:13 UTC, Juanjo Alvarez wrote:
 Hi!

 With "alias this" accepting runtime variables I'm struggling to
FYI, you are not talking about "alias this", but "alias template parameters", two very different concepts.
 understand the difference between a generic function with an 
 "alias this" parameter and another one with a "runtime" 
 parameter of template type.

 Example:

 // ---- example code ----
 import std.stdio: writeln;

 void writevalue1(alias param)() { writeln(param); }

 void writevalue2(T)(T param) { writeln(param); }

 void main() {
   import std.random: uniform;
   auto someNum = uniform(0, 1000); // runtime value
   writevalue1(someNum);
   someNum = uniform(0, 1000);
   writevalue2(someNum);
 }
 // ---- example end -----

 Since both versions work with runtime values, what's are the 
 differences? When I should prefer one version over the other?
Neither template cares or knows anything about runtime values. When the compiler encounters them, it instantiates an instance of each by creating functions that work with runtime values. But it does so differently for each. In your instantiation of writevalue1, you are passing the symbol "someNum" as an alias template parameter. This instantiation will only ever be used with "someNum". If you pass it a different symbol, you'll get a separate instantiation, even if it has the same type as "someNum". In your instantiation of writevalue2, you are getting a function that takes a single argument of `typeof(someNum)`. This instantiation will be used for any value you pass to it that has the same type. If you're only interested in the value of a variable, you almost certainly want to use template type parameters most of the time, especially if you are going to be calling the function with multiple variables. That way, variables of the same type all have one instantiation and you avoid bloat. Use alias parameters when you actually care about the *symbol* and not the value.
Apr 12
prev sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 12 April 2017 at 11:06:13 UTC, Juanjo Alvarez wrote:
 Hi!

 With "alias this" accepting runtime variables I'm struggling to 
 understand the difference between a generic function with an 
 "alias this" parameter and another one with a "runtime" 
 parameter of template type.

 Example:

 // ---- example code ----
 import std.stdio: writeln;

 void writevalue1(alias param)() { writeln(param); }

 void writevalue2(T)(T param) { writeln(param); }

 void main() {
   import std.random: uniform;
   auto someNum = uniform(0, 1000); // runtime value
   writevalue1(someNum);
   someNum = uniform(0, 1000);
   writevalue2(someNum);
 }
 // ---- example end -----

 Since both versions work with runtime values, what's are the 
 differences? When I should prefer one version over the other?

 If objdump is not lying to me, both calls jump to the same 
 assembly and the only diffence is that the call to writevalue1 
 does a "mov -0x8(%rdi),%edi" just before the callq instruction.
(As noted by Mike the examples you present are actually template alias parameters, not alias this which affects name lookup.) There are three kinds of template parameters types, values and aliases. I assume you understand what the first two _do_ in terms of parameterisation. Alias parameters are for symbols, and are used generally when the thing you want to template on not a value or a type (although alias parameters can accept anything). These typically include lambdas e.g. the predicate to std.algorithm.filter or the transformation to std.algorithm.map, (global) variables to do introspection (for e.g. logging).
Apr 12
parent Juanjo Alvarez <gorthol protonmail.com> writes:
Thanks to both, I got it. Type templates for generic types, and 
alias for other things knowing that the instantiation is by 
symbol.

Yes, the "alias this" in my message  was a (double) brainfart, I 
actually wanted to write "alias template".

In this case both functions had the same assembler body which was 
part of what had me confused but I guess that's a compiler 
optimization.
Apr 12