On Monday, 8 April 2019 at 12:23:28 UTC, Ron Tarrant wrote:
I'm digging into templates in an attempt to understand the signals-n-slots replacement for the observer pattern, but I've got a question I can't seem to find an answer for and an example for which I'm unable to solve the error.

First, the question...


Your confusion arises in your understanding of meta programming and templates. Templates are compile time expressions that use parameters. They are exactly analogous to parameters in typical programming but allow one to pass around CT information that doesn't exist at run time.

It is not the statement itself that is a template but the fact that it depends on a "template", which is a sort of abstract variable.

class C(T)

template C(T)

struct(T)

interface(T)

void foo(T)()

etc...


are all things that depend on a template parameter T. One can say that they are all "templated" or are "templates".

One can also say they are parameterized(meaning they take a parameter, but the parameters are CT "objects".


Essentially template is the most general and the rest are just syntactic sugar.

e.g.,

template CC(T)
{
   class C
   {
      T t;
   }
}


template CC is a "template"(just like a cookie cutter but that can configure itself depending on what T is, as this example shows that we can create a class with different type of t.


D has all kinda of stuff like this that help reduce the bloat of templates. Sometimes you must use one method over another for certain effects but usually you can pick and choose.

The idea is not to think of meta programming as something different than normal programming. It is still programming and there is enough of an overlap that it benefits one to realize they are the same thing but are at different levels in the type system. Meta programming works on the type hierarchy while "runtime programming" works in the type hierarchy. Meta programming is a super set of runtime programming.


The way I think of meta programming is that of coding runtime code. Run time code codes binary code. If I create a statement like

writeln("test");

I know that the code gets translated in to a call instruction, pointers are used, "test" exists in some location in memory, etc... it all is machine code though when I compile.

When I do something like this

foo!int();

I know that the first part of foo!int is "meta code" and it first gets translated in to runtime code and then that code gets translated in to machine code.

For example

void foo(T)(T s) { writeln(s); }

in this case, depending on what T is at compile time(which I get to decide in some way and so I know exactly what it is at compile time, in theory), foo takes on different versions.

if I call foo(3) then it is writeln(3) and T is an int(by deduction in the compiler) and the compiler can even optimize out certain things here because it also knows that 3 is known.(this is CTFE) There is nothing to optimize in that example though.

if I call foo(readln()) then the the compiler cannot optimize out but this code get translated in to writeln(readlin()) but T is a string(since readln returns a string and the compiler can deduce it).

But in general foo acts as all these possibilities(and all the possibilities are known by the compiler because they have to be known to compile and use).

So, what does templates do? They combine very similar code in to meta blocks that can then be easily used. They allow constructing very complex meta code such as

void foo(T)(T s) { static if (is(T == string)) writeln(s); }


and now foo is much more complicated because it has two completely different behaviors depending on what T is. You can't get that with run time code without a lot of work and it will never be efficient. But here the compiler will eventually know what T is and it can then choose the correct path at compile time. The if will disappear and so no extra overhead exists at runtime.

So, templates are very powerful things(the above doesn't even dent their power) The idea to bear in mind is that anything in D is a template if it takes a template parameter. Think of a template as a drawing template used to sketch something. It isn't the final result but it shapes the final result. It is more like a blueprint or a program in and of itself.

I think the hard part for many is that they can't balance the meta programming part with the run time part. This is very easy though if one always just keeps track of which side one is programming in and not to mix them up(mentally).

The meta programming part will always be obvious, it will depend on template parameters and use meta programming constructs. There are sometimes overlap between the two levels but it because natural once one gets enough of an understanding.

The hardest part about D is that it has so much meta programming stuff and there are sometimes bugs and special cases to do things, but the grammatical design of it's type system is very nice and sane compared to most other procedural programming languages.


Always keep in mind that the templating system is about creating "generic" code. source code that generates source code(D could spit out a non-templated source code version if it was designed to) which then generates machine code.

Each higher level allows one to organize levels below it and create generic solutions to problems.

Ideally we would have even higher levels but programmers haven't evolved to this point yet(maybe some functional languages have).



Reply via email to