How Do Multimethods Interact with Modules?
module a def double(i Int) i * 2 end module b def double(s String) s ~ s end module c import a import b double(1) double("s") end
import means, "get all of the top-level identifiers in the given module and copy them into this one", then that code has a problem. Modules
b each define multimethods bound to top-level variables
double. When we hit
import b, it will either have a name collision when it imports
double again, or it will overwrite. In neither case will the code do the right thing.
This is a bummer since namespaced methods was the motivating factor for multimethods (i.e. not tied to class generic functions) to begin with. What's the solution?
One option would be to not make multimethods first-class. Right now, they're just objects bound to a variable. Named dispatch looks up the variable, finds a multimethod in it, and goes from there. This means that they're pretty opaque when it comes to things like
On the other hand, it means you can pass them around as objects. Except you actually can't because there's no syntax to just get one. If you have a multimethod stored in
foo, then just doing
foo won't get it. Instead, it will try to invoke it as a getter on the current (implicit) receiver: i.e. it calls
So, since they aren't very first-class like anyway, one option would be to make them explicitly not first class and more built into the language as a module-level construct. When you declare a method, it adds it to the current module. When you import it, it just merges it with any methods of the same name in the current module.
This makes them very different from functions, which are normal, lexically scoped first-class objects. It's clear that functions are still needed for things like
with and higher-order functions like
filter. Is it redundant or confusing to have both?
There's already some difference between a method and a function even in single-dispatch Magpie since
this has different semantics between the two. This pushes them farther apart, but that may not be a bad thing.
One consequence of this is that there's no way to make a "local" multimethod. Regardless of where the
def appears, they live at the module level. That covers 95% of the use cases, but is a limitation. At the very least, it will make the spec a little trickier since it wants to scope things as locally as possible.
This also feels like it goes against the grain of the language since pretty much everything else is lexically scoped: functions, classes, variables.
Perhaps a more straightforward solution is to simply merge multimethods on import. If you import a named multimethod and there is already a multimethod with that name in the current module, just merge them.