Minor problems with templates and mixins

Tom S h3r3tic at remove.mat.uni.torun.pl
Tue May 23 06:09:59 PDT 2006


While D's template system is really excellent, it's still got minor 
problems. One is related to the current way to define function 
templates. The other is about mixins - they seem to have a really 
awkward nature.

* The two issues I present are by no means showstoppers, but rather 
language details that make it unpleasant to use in a few cases.


1. Can't overload functions inside templates, e.g. the following code 
won't work

# template foo(T) {
#     T foo(int  a) { return T.init; }
#     T foo(char a) { return T.init; }
# }
#
# void main() {
#     foo!(float)(1);
# }

Yeah, the spec mentions that to be able to write foo!(float) instead of 
foo!(float).foo, the template must have exactly one symbol in it, yet 
it's not very comfortable to work with.

It's possible to partially work around this limitation, e.g.

# private import std.stdio;
#
# template foo(T) {
#     static struct foo {
#         static T opCall(int  a) { writefln("int");  return T.init; }
#         static T opCall(char a) { writefln("char"); return T.init; }
#     }
# }
#
# void main() {
#     foo!(float)(1);
#     foo!(char)('a');
# }

But this idea breaks when the function template is meant to be a 
non-static member of some class.


2. The spec for mixins states "Unlike a template instantiation, a 
template mixin's body is evaluated within the scope where the mixin 
appears, not where the template declaration is defined. It is analogous 
to cutting and pasting the body of the template into the location of the 
mixin". Yet the following code doesn't compile:

# template A() {
#     template foo(T : int) {
#         void foo() {
#         }
#     }
# }
#
# template B() {
#     template foo(T : char) {
#         void foo() {
#         }
#     }
# }
#
# mixin A;
# mixin B;
#
# void main() {
#     foo!(char)();
# }

Also, aliasing the foo function template out of A doesn't work:

# alias A.foo foo;
# alias B.foo foo;


In both cases, conflicting symbols are reported by DMD. On the other 
hand, the following code does compile:

# template foo(T : int) {
#     void foo() {
#     }
# }
#
# template foo(T : char) {
#     void foo() {
#     }
# }

# void main() {
#     foo!(char)();
# }

Which clearly illustrates that mixins are not like copy and paste. But 
that's pretty obvious even due another sentence from the spec "A mixin 
has its own scope". Copy-and-paste doesn't.
IMHO, mixins should have their scope, but except for that, they should 
behave like parametrized copy and paste...


Similarly, the following code also produces errors:

# template foo(T) {
#     void foo(T x) {
#     }
# }
#
# alias foo!(int).foo     foo;
# alias foo!(char[]).foo  foo;
#
# void main() {
#     foo(1);
# }


Although this works just fine:

# void fooInt(int x) {}
# void fooStr(char[] x) {}
#
# alias fooInt foo;
# alias fooStr foo;
#
# void main() {
#     foo(1);
# }


Have I missed any important details ? Are there already good workarounds 
for these issues ?
All constructive criticism is welcome ;)



-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d-pu s+: a-->----- C+++$>++++ UL P+ L+ E--- W++ N++ o? K? w++ !O 
!M V? PS- PE- Y PGP t 5 X? R tv-- b DI- D+ G e>+++ h>++ !r !y
------END GEEK CODE BLOCK------

Tomasz Stachowiak  /+ a.k.a. h3r3tic +/



More information about the Digitalmars-d mailing list