Skip to content

Instantly share code, notes, and snippets.

@kennytm
Created April 25, 2011 14:12
Show Gist options
  • Save kennytm/940565 to your computer and use it in GitHub Desktop.
Save kennytm/940565 to your computer and use it in GitHub Desktop.
Multiple dispatch in D
import std.traits, std.typetuple;
template GeneralizeType(T) {
static if (is(T == class))
alias Object GeneralizeType;
//@@@BUG@@@ Should preserve qualifier of T.
else
alias T GeneralizeType;
}
mixin template ImplementMultipleDispatch(alias method, alias Parent = __traits(parent, method)) {
private enum methodName = __traits(identifier, method);
private alias staticMap!(GeneralizeType, ParameterTypeTuple!method) ParamType;
//@@@BUG3543@@@ Should take the most common type from all overloads of the
// method, but currently it is very complicated due to 3543, so
// we just default to use Object.
alias method opCall;
static auto opCall(ParamType params) {
writeln(" ***called the multiple dispatch method");
foreach (overloadedMethod; __traits(getOverloads, Parent, methodName)) {
//@@@BUG@@@ Should sort overloads by specialization.
//@@@BUG@@@ Should inherit function attributes from the method
ParameterTypeTuple!overloadedMethod specializedParam;
bool matched = true;
foreach (i, T; ParameterTypeTuple!overloadedMethod) {
specializedParam[i] = cast(T)params[i];
static if (is(T == class))
if (specializedParam[i] is null) {
//@@@BUG@@@ What if it is not a parameter for dispatch
// but is null? Need to check that.
matched = false;
break; // continue label doesn't work.
}
}
if (matched)
return overloadedMethod(specializedParam);
}
throw new Exception("Cannot find suitable overload in " ~ methodName);
}
}
//------------------------------------------------------------------------------
import std.stdio;
class A : Base {}
class B : Base {}
class Base {
static private {
int someFuncImpl(A x, A y, B z, B w, double t) {
writeln("A, A, B, B, ", t);
return 3;
}
int someFuncImpl(A x, B y, A z, B w, double t) {
writeln("A, B, A, B, ", t);
return 2;
}
int someFuncImpl(A x, A y, A z, A w, double t) {
writeln("A, A, A, A, ", t);
return 1;
}
}
mixin ImplementMultipleDispatch!someFuncImpl someFunc;
}
void main() {
Base base = new Base();
Base a = new A();
Base b = new B();
A aa = new A();
B bb = new B();
assert(1 == Base.someFunc(aa, aa, aa, aa, 0.4));
assert(3 == Base.someFunc(aa, aa, bb, bb, 0.3));
assert(1 == Base.someFunc(a, a, a, a, 0.5));
assert(3 == Base.someFunc(a, a, b, b, 0.6));
assert(2 == Base.someFunc(a, b, a, b, 0.7));
Base.someFunc(b, b, b, b, 0.8); // throws
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment