const debacle

e-t172 e-t172 at akegroup.org
Sat Mar 22 04:21:24 PDT 2008


Janice Caron a écrit :
> Why am I suggesting this? Well, bear with me. All will become clear
> shortly. The next step is to introduce a new kind of template
> parameter:
> 
>     template T(const K)
>     {
>         ...
>     }

The problem of this solution is that you're basically using templates to 
solve a problem which will probably affect a LOT of functions 
(especially text processing functions).

I think we should keep in mind that :
  - most of libraries are distributed in shared form (at least on Unix), 
because shared libraries are far more practical;
  - templates themselves cannot be compiled, so they cannot be included 
in a shared library, they are "compiled" when the code that instanciates 
them is compiled (which basically is the same as using static libraries)

This means that when you are over-using templates, you lose all the 
advantages of shared libraries. I think a lot of people easily forget 
about this; for example, in Tango text.Util:

T[] trim(T) (T[] source)
T[] strip(T) (T[] source, T match)
T[][] split(T) (T[] src, T[] pattern)

etc... nearly all functions in this module are templates, in order to 
support char, dchar and wchar without duplicating code. This basically 
means that when we'll be able to compile Tango in a shared library, this 
module will be compiled to... nothing. This means that when the code of 
this module is modified, ALL projects using it must be recompiled to use 
the new module. Now imagine that D become very popular (which I hope 
will happen), this will become very hard to manage (if you don't 
understand why, imagine what would happen if the libc was linked 
statically in all executables of your system...)

In the case of Tango, we can address this issue by writing this in 
text.Util:

char[] trim(char[] source) { return trim!(char)(source); }
dchar[] trim(dchar[] source) { return trim!(dchar)(source); }
wchar[] trim(wchar[] source) { return trim!(wchar)(source); }

And so on for all functions. However, it is not very elegant. A better 
idea would be to include a new "feature" in D 2.0, i.e. "compiled 
templates", with a new syntax like this :

T[] trim(T # [char,dchar,wchar]) (T[] source)

This will behave exactly like the original syntax, except that when you 
compile text.Util, trim() will be included in the object file in three 
versions: char, dchar and wchar. Now when the caller writes 
trim!(char)(foo), the compiler WILL automatically use the already 
compiled "char" version of trim(). And if you want to do something 
exotic, like trim!(mytype)(foo), it will still be possible, but it will 
behave like a "classic" template, that is, the template code will be 
compiled into the code that instanciates it.

The point here is to allow the compiler to generate object code for 
templates which get only used with a small subset of types 99% of the 
time (like these functions in Tango, which are only used with char, 
dchar and wchar), in order to render shared libraries more useful and 
practical.

Of course, "pure templates", that is, templates which are meant to be 
instanciated and used with any given type as parameter, cannot benefit 
from this "feature".

So, back to the point, in your case :

 >     template T(const K)
 >     {
 >         K char[] f(K char[] buf ) { ... }
 >     }

Would become :

      template T(const K # [auto,const,invariant])
      {
          K char[] f(K char[] buf ) { ... }
      }

A better solution: each "const K" template construct is always compiled 
in the three versions (or rather in one version, because the object code 
for the three is identical).



More information about the Digitalmars-d mailing list