Multiple dispatch is commonly used for fixing the "expression problem". http://en.wikipedia.org/wiki/Expression_problem
This is usually easily done in functional languages, and relates to the best way to adapt existing code to new uses, without changing the underlining code. Multimethods provide a very good solution to the problem. http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Dr-Ralf-Laemmel-Advanced-Functional-Programming-The-Expression-Problem http://www.ibm.com/developerworks/java/library/j-clojure-protocols/?ca=drs- -- Paulo "Adam D. Ruppe" <destructiona...@gmail.com> wrote in message news:iovuf1$2dhi$1...@digitalmars.com... > bearophile wrote: >> [multiple dispatch and what they use it for.] > > I wonder if we could do it in the library by using overloads and > a generated dynamic cast. > > class Base { > // if the types are known, regular overloading does the job > void multipleDispatchFun(A a, A b) { writeln("Called (A, A)"); } > void multipleDispatchFun(A a, B b) { writeln("Called (A, B)"); } > void multipleDispatchFun(B a, B b) { writeln("Called (B, B)"); } > } > > class A : Base {} > class B : Base {} > > void main() { > Base base = new Base(); > Base a = new A(); > Base b = new B(); > > // doesn't compile - static types don't match > base.multipleDispatchFun(a, b); > > // So, we'd have to cast it ourselves and try to call > if(dynamic casts are ok) > base.multipleDispatchFun(cast(A) a, cast(B) b); // would work > } > > > It's that last part that multiple dispatch solves (someone > correct me if I'm wrong). It's a pain to do manually. > > But maybe D can do it automatically. We can generate another > overload that takes the base class, tries to cast to all the > existing overloads, and if not null, go ahead and call it. > > This isn't complete, but it works for this simple case so it's a > start and proof of concept: > > ========= > > import std.traits; > > template implementMultipleDispatch(alias Class, alias method) { > //pragma(msg, multipleDispatchImpl!(Class, method, > // __traits(identifier, method))()); > > // mixing it in right here didn't work for some reason > alias multipleDispatchImpl!(Class, method, > __traits(identifier, method)) implementMultipleDispatch; > > } > > // straight stringof hit a problem with forward reference, so this hack > will > // do it > > string[] parameterTypeStrings(string methodString)() { > string[] ret; > > int startingAt; > int state = 0; > foreach(idx, c; methodString) { > switch(state) { > // first, we find the opening param > case 0: > if(c == '(') { > state++; > startingAt = idx + 1; > } > break; > case 1: // we're reading a type name > if(c == ' ') { > // just finished > ret ~= methodString[startingAt .. idx]; > state = 2; > } > break; > case 2: // now we're reading a name > if(c == ' ') { > state = 1; // another type > startingAt = idx + 1; > } > if(c == ')') // we're done > //break loop; > state = 3; > break; > // we're done, but break loop doesn't work in CTFT > case 3: // do nothing with the rest > } > } > > return ret; > } > > string multipleDispatchImpl(alias Class, alias method, string > methodName)() { > string code = `void ` ~ methodName ~ `(`; > > alias typeof(__traits(getOverloads, Class, methodName)) overloads; > > string baseType = Class.stringof; > bool outputted = false; > > // we'll reuse the call string to make our calls > string call = methodName ~ "("; > char arg_char = 'a'; > foreach(arg; ParameterTypeTuple!(method)) { > if(outputted) { > code ~= ", "; > call ~= ", "; > } else > outputted = true; > > code ~= baseType ~ " " ~ arg_char; > call ~= " " ~ arg_char ~ "_casted"; > arg_char++; > } > > call ~= ");"; > code ~= ") {"; > > foreach(overload; overloads) { > > code ~= "{"; // we'll introduce a scope to do our casts > string ifCheck; // this lists the checks for null > outputted = false; > arg_char = 'a'; > > foreach(argument; parameterTypeStrings!(overload.stringof)) { > // just try to cast all of them > code ~= "auto "; > code ~= arg_char ~ "_casted = cast("; > > code ~= argument; > > code ~= ") " ~ arg_char ~ ";"; > > if(outputted) > ifCheck ~= " && "; > else > outputted = true; > > ifCheck ~= arg_char ~ "_casted !is null"; > > arg_char++; > } > > // if none of the args are null, it's safe to do the call > code ~= "if(" ~ ifCheck ~ ") {"; > code ~= call ~ "return;"; // return because we're done > code ~= "}"; // end if > code ~= "}"; // close our casting scope > } > > code ~= "}"; > > return code; > } > > ============== > > > > Here's a test using it: > > import std.stdio; > > // copy paste the above in here > > > class A : Base {} > class B : Base {} > > class Base { > void multipleDispatchFun(A a, A b) { writeln("Called (A, A)"); } > void multipleDispatchFun(A a, B b) { writeln("CORRECT Called (A, B)"); } > void multipleDispatchFun(B a, B b) { writeln("Called (B, B)"); } > > mixin (implementMultipleDispatch!(typeof(this), multipleDispatchFun)); > } > > > void main() { > Base base = new Base(); > Base a = new A(); > Base b = new B(); > > // calls the generated base class overload > base.multipleDispatchFun(a, b); > > // and, of course, if the static types are known, the > // regular overload works fine. only problem is if one > // is statically known and one is not. Then you shoud > // cast to the base type manually so it triggers the > // generated overload > } > > ======== > > > This is a toy example, but if someone really wanted to spend the > time, I think it proves it can be done for real examples too, at > least in theory.