This is why I spent a section on showing the "failed attempt". It's surprising how many folks don't understand the difference between overloaded functions (compile-time dispatch) and true multiple dispatch (at run time).
Visitor pattern always blows people's minds when they first see it in action hehe.
Would it be more surprising to Java newbies if it did work that way?
Multiple dispatch screams for the abolishment of methods as properties of objects, in favor of generic functions.
Youc an still have the syntactic sugar obj.foo(arg), but it basically just translates to foo(obj, arg) where foo is a generic function not associated with foo's class in any way, and obj and arg have equal status.
This generic function is what has methods.
Multiple dispatch screams for the abolishment of methods as properties of objects, in favor of generic functions.
Youc an still have the syntactic sugar obj.foo(arg), but it basically just translates to foo(obj, arg) where foo is a generic function not associated with foo's class in any way, and obj and arg have equal status.
This generic function is what has methods.
Say we implemented "funky" numbers, and would like to implement multiplication of funky and real. When funky is the left argument we get funky.mult(real). If real is no the left, we get real.mult(funky). These functions do the same thing (the multiplication is commutative), yet ... they have to live in separate classes? It is nonsensical.
Under generic functions, we just have mult(real, funky) and mult(funky, real) which are methods of the generic mult(whatever, whatever). They both belong to the one generic function: that is the more reasonable organization.
One benefit is that the name `bar` is looked up in `foo`'s namespace, which means that it doesn't have to be in the current global namespace. This is a mixed blessing, but it's sometimes what you want.
These name spaces do not have to be conflated with program lexical scopes, whereby if you are a piece of code such and such a "blessed" function, you "see" the name space of the class as if it were lexical variable bindings.
You definitely don't want crud like different scopes in the program which are all working with exactly the same object, and want to access slot S, but they all refer to a different S because they are associated with a different place in the inheritance hierarchy, and that hierarchy contains unrelated slots named S at different levels. A given object must just have one S.
class Bar
def foo(baz :: Baz)
...
end
end
def foo(bar :: Bar, baz :: Baz)
...
end
could be in this hypothetical language that the former would be allowed to access private member variables on bar = Bar.new, while the latter wouldn't.The questions then are:
a) Is private state something we want?
b) Could private state access control be implemented in a different way (Lexically? Package level? Additional annotation?)
The idea of friend functions of a class could be adapted from C++.
It could work dynamically like this.
Firstly, given obj.slot or obj.fun(); if the type of obj is not known in the given scope, then these accesses are disallowed unless slot and fun are public.
Secondly, a class can be (dyamically) associated with a (dynamically extensible) list of friend generic functions.
When a new method is being compiled for a generic function, the compiler uses the class information about the argument (which specializes it) to check the friend list of that class. Then inside the friend method, obj.slot and obj.fun() are allowed even if slot and fun are private.
(Friendship of compiled code couldn't be revoked; once a method is processed by at least the expanding code walker, if not compiled, then it cannot lose access even if the generic function is removed from the friend list of that class.)
Firstly, obj.member could be disallowed if
I think this comment sums it up well: https://news.ycombinator.com/item?id=11528588