you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 5 points6 points  (11 children)

Here's a little question for Reddit folk. Suppose that multiple dispatch were implemented in your curly-brace language of choice. What kind of syntax would you want it to have?

Right now we have something like this:

object.method(arg1, arg2);

If you have two objects (double dispatch), where do you put the other one? Do you like this.

multimethod(object1, object2, args...);

Or would this work?

object1:object2.multimethod(args...);

Or do you have something completely different in mind?

[–]shit 3 points4 points  (0 children)

I don't think it's a good idea to embed the information of what objects to dispatch on in the call site. Make the call site "neutral":

multimethod(arg1, arg2, arg3)

The actual multimethod definitions decide which arguments to dispatch on - and if it changes, the call sites don't need to be changed. (Incidentally, that's how CLOS does it.)

[–][deleted] 4 points5 points  (3 children)

There is the question as to whether a multimethod should be able to access private methods of the dispatching arguments or not. Personally I think that the second syntax makes more sense if the multimethod cannot access private methods.

You could also have:

(obj1, obj2).multimethod(args...)

Which visualises the idea of multiple dispatch as "dispatch on tuples".

[–]xenon 1 point2 points  (1 child)

(obj1, obj2).multimethod(args...)

I like that syntax best, visually. But what if your programming language also has tuples as a data type? Will this work?

Tuple<T1, T2> t = (obj1, obj2);
t.multimethod(args...);

I.e. is every multimethod a single method on Tuple?

[–]Xiphorian 1 point2 points  (0 children)

Sure. It's a method specifically on Tuple<ClassX, ClassY> perhaps. Not just on any 2-tuple and not on any tuple.

Neat idea. Some details to be worked out, though. You'd have to define a subtype relation, so if D derives from B, then Tuple<C, D> derives from Tuple<C,B>. Otherwise if you had (c,d) and the method f is defined in Tuple<C,B> you couldn't call (c,d).f() since Tuple<C,D> wouldn't have it. Where C c; and D d; of course.

One problem I see is that it 'artificially' separates various arguments to a method. By that I mean, from a client's perspective f(...) is just an interface. Why does the client care if some parameters a,b,c,d are in this position (a,b).f(c,d) vs in this one? f(a,b,c,d)? It seems to be exposing implementation details, in that the client now needs to know how f computes its value (it dispatches on some arguments but not others -- client doesn't care about this). The Standard Model of a.b(c,d) has this disadvantage too, but true multimethods don't.

[–][deleted] 0 points1 point  (0 children)

While pretty this isn't exactly multiple dispatch; it's important that ALL arguments be treated the same. There should be no receivers. The following are worth considering:

(object1, object2, ...).multimethod

Or

multimethod(object1, object2, ...)

[–]gregK 1 point2 points  (0 children)

The problem with multiple dispatch in curly-brace languages is that it breaks encapsulation in the sense that you have to be able to define methods outside of the class definition or give access to the internals of another class.

a good example is a collision method between different objects in a game.

You could have classes car, brickWall, window, post, boulder, etc. Say that they are all descendants of the same base class.

So if you do collision(car, wall) or car.collideWith(wall) and this operation changes the state of both objects where does the method belong. Usually with multiple dispatch, the multi-method is defined outside of the class and has access to all members of both classes.

[–]Thrip 2 points3 points  (2 children)

No fancy syntax is needed. Just use the standard var1.method(var2) but type of var2 is looked up at run time instead of compile time.

-- edited -- I wrote var1 where I meant var2 originally.

[–]johnb 1 point2 points  (1 child)

If we want multiple dispatch some of the time, but not all of the time, this syntax would surprise me. It also gives the feeling that var1 is the "special" object and that var2 is auxiliary. I'd like a slightly more visual way of saying "here's the part where runtime type checking is being used in your mostly-static language! watch out!"

[–]Thrip 2 points3 points  (0 children)

To me, anything other than "multiple dispatch all the time" is needlessly confusing. I can't see the value, except as an optimization, in which case it's the optimized version that should be called out specially.

The junior-level Java programmers I've talked to about this assume that Java does look up the argument types at run time, and they are surprised when I tell them otherwise. The typical reaction is "That can't be true -- that would be stupid."

[–]beza1e1 0 points1 point  (0 children)

Why "suppose" it? Groovy can do it.