D allows overriding operators like +, - or
the call operator () for
classes and structs.
We will have a closer look at the two special
operator overloads opDispatch and opApply.
opDispatch can be defined as a member function of either
struct or class types. Any unknown member function call
to that type is passed to opDispatch,
passing the unknown member function's name as a string
template parameter. opDispatch is a catch-all
member function and allows another level of generic
programming - completely at compile time!
struct C {
void callA(int i, int j) { ... }
void callB(string s) { ... }
}
struct CallLogger(C) {
C content;
void opDispatch(string name, T...)(T vals) {
writeln("called ", name);
mixin("content." ~ name)(vals);
}
}
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");
An alternative way to implementing a foreach traversal
instead of defining a user defined range is to implement
an opApply member function. Iterating with foreach
over such a type will call opApply with a special
delegate as a parameter:
class Tree {
Tree lhs;
Tree rhs;
int opApply(int delegate(Tree) dg) {
if (lhs && lhs.opApply(dg)) return 1;
if (dg(this)) return 1;
if (rhs && rhs.opApply(dg)) return 1;
return 0;
}
}
Tree tree = new Tree;
foreach(node; tree) {
...
}
The compiler transforms the foreach body to a special
delegate that is passed to the object. Its one and only
parameter will contain the current
iteration's value. The magic int return value
must be interpreted and if it is not 0, the iteration
must be stopped.