Reloaded a protocol and "No implementation of method"?
While protocols provide a nice way to program to interfaces, they do have some unfortunate interactions with repl driven development. It’s annoying to be working along, reload a file, and then BOOM.
But this code was just working! My
Rectangle
implementsDrawable
. It’s right there. I can see it in the code!
Having code that looks like it should work, but getting runtime errors is annoying. Getting ones that aren’t immediately understandable, about code that was just working, can frustrate anyone.
So what causes this error?
To duplicate this error imagine working on two files.
Loading these files into a repl works. Calling draw-many-rectangles
outputs something expected.
Now imagine having to change what the output is. Perhaps instead of a list of strings draw-many
needs to return a single string.
A common workflow is to reload a file into a repl once editing it is done. This could be with cider’s C-c C-x
, or clojure’s load
and load-file
functions. Doing this for the z.draw
namespace and attempting to run (draw-many-rectangles)
will cause an error.
This happens because when the z.draw
namespace was reloaded it created a new protocol with the same name. But the z.core
namespace was evaluated with the previous reference. It’s defrecord
referred to the old version of Drawable
. When creating a Rectangle
it will implement the old protocol.
How to fix
The z.core
namespace needs to be reloaded. Then it will redefine Rectangle
and refer to the correct Drawable
. This can be done by using the same load-file technique that loaded z.draw
.
Doing this by hand can be annoying. There are techniques to reduce the possibility of encountering this. One is to only define a protocol in a other wise empty namespace. All other functions go elsewhere. Then these types of errors can only occur when changing the protocol definition.
A tooling based solution is to use tools.namespace and something similar to reloadable systems in order to reload your entire application at once. I’ve been told cursive’s “Load File in REPL” command implements a similar namespace reloading mechanism.