Templates everywhere

Max Samukha spambox at d-coding.com
Mon Mar 15 05:20:24 PDT 2010


On 15.03.2010 3:42, Walter Bright wrote:
> Bane wrote:
>>> ======= C++ =========
>>> template<class T> class Foo
>>> {
>>> T member;
>>> };
>>> ======= D ===========
>>> class Foo(T)
>>> {
>>> T member;
>>> }
>>> =====================
>>>
>>> Yes, it looks like a trivial change, and perhaps it is. But it makes
>>> a world of difference, because it now looks like something I do get -
>>> a parameter list to something.
>>
>> Fucking beautiful. I finally get it.
>
>
> Ya know what's funny? I had to go and double check that the C++ syntax
> above was correct. Didn't have to do that for D.

Though I love D's templates:

1. People tend to throw them in where a runtime solution would suffice. 
One example is an overload of 'clear' in the D runtime:

void clear(T)(T obj) if (is(T == class))
{
     auto defaultCtor =
         cast(void function(Object)) obj.classinfo.defaultConstructor;
     version(none) // enforce isn't available in druntime
         _enforce(defaultCtor || (obj.classinfo.flags & 8) == 0);
     immutable size = obj.classinfo.init.length;
     static if (is(typeof(obj.__dtor())))
     {
         obj.__dtor();
     }
     auto buf = (cast(void*) obj)[0 .. size];
     buf[] = obj.classinfo.init;
     if (defaultCtor)
         defaultCtor(obj);
}

Since the function uses runtime information (except for the destructor), 
it is absolutely unnecessary to instantiate the template for each 
concrete class type. A more severe problem with the code above, 
unrelated to templates, is that base class destructors are not called.

Here is a non-template implementation that should fix the problems (it 
is a template but only formally):

void clear(Dummy = void)(Object obj)
{
     auto ci = obj.classinfo;
     auto defaultCtor =
         cast(void function(Object)) ci.defaultConstructor;
     version(none) // enforce isn't available in druntime
         _enforce(defaultCtor || (ci.flags & 8) == 0);
     immutable size = ci.init.length;

     auto ci2 = ci;
     do
     {
         auto dtor = cast(void function(Object))ci2.destructor;;
         if (dtor)
             dtor(obj);
         ci2 = ci2.base;
     } while (ci2)

     auto buf = (cast(void*) obj)[0 .. size];
     buf[] = ci.init;
     if (defaultCtor)
         defaultCtor(obj);
}

BTW, I do think that base class destructor calls not compiled directly 
into derived class destructors is a mistake.

2. Templates impose functional style on programmers (see Bartosz's rant 
at 
http://bartoszmilewski.wordpress.com/2009/10/21/what-does-haskell-have-to-do-with-c/).



More information about the Digitalmars-d mailing list