Description
Consider this code:
defmodule Foo
def read
:foo_read
end
end
deftype Bar
include Foo
def read(something)
:bar_read
end
end
%Bar{}.read
I would expect this code to return :foo_read
, since the read
clause defined in Bar
does not match the arguments given in the Call at the end of the sample.
What actually happens, though, is a "No clause matches" error is raised, because the method lookup does not continue into the Foo
module.
The reason for this is that Bar
and Foo
have separate TFunctor
objects representing the read
method. Each has one clause, and exists in its respective scope.
When method lookup starts, the interpreter will check Bar
and find its TFunctor
for the method. The only clause here requires a parameter, but the Call itself does not provide any arguments. As such, the Invocation of the method fails and the error is raised.
I think there are probably a few good ways to resolve this. The first that comes to mind is changing how Invocation
works to allow multiple TFunctor
objects to be bound, and it will iterate them in order to find a matching clause.
Another option I thought of was cloning the TFunctor
object from the included module into the object that included it, allowing that object to have a single functor with all of the clauses together. However, this approach would still have an issue where re-opening the module and adding a clause would not add that clause to anything that includes that module.