Created
April 25, 2011 14:12
-
-
Save kennytm/940565 to your computer and use it in GitHub Desktop.
Multiple dispatch in D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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