| |
 | Posted by Tom S | Permalink Reply |
|
Tom S 
| 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 +/
|