I seem to have stumbled into something similar to what was mentioned in this thread: Function overriding causes warning
however, I can’t spot the trouble.
I have a “base” module that provides some default implementations of functions (i.e. not functions that are optional in any way that could be notated via @optional_callbacks
). 90% of the time, the default implementation is what’s used. But when I do need to override the one of these functions, I keep seeing warnings, .e.g
warning: this clause for foo/1 cannot match because a previous clause at line 8 always matches
lib/my_app/foo.ex:130
My tests are passing – the proper code is getting executed. Can anyone shed light on the source of the warning? I have the proper use
statement in my modules, so I’m wondering if there’s something else I’ve missed.
1 Like
Can you provide a working example? It’s hard to tell what’s going on here, but I suspect its due to how the use
macro is being expanded.
1 Like
It boils down to something like this
defmodule Defaults do
defmacro __using__(opts) do
quote do
@impl true
def foo do
Defaults.parent_foo(unquote(opts[:x]), unquote(opts[:y]))
end
defoverridable foo: 0
end
end
def parent_foo(x, y) do
x + y
end
end
defmodule Child1 do
use Defaults, x: 12, y: 14
end
defmodule Child2 do
use Defaults, x: 13, y: 15
def foo do
Defaults.parent_foo(1, 3)
end
end
Which seems to be working fine without warnings… so this gives me something to hack on. I’ll build this POC up until it matches my actual code or it generates the warning.
Without the detail of the warning, I can only guess the cause. Does the following modification help?
defmodule Defaults do
@callback foo() :: integer() # <-- add this line
defmacro __using__(opts) do
quote do
@behaviour unquote(__MODULE__) # <-- and this line
#...
end
end
end
You’ll want to use @before_compile
to put the default implementations at the end of the module instead of at the top (where use …
is located). Then any custom implementation comes before your generated one. If you still get a warning you can use generated: true
on the quote do
block with the generated default implementation to prevent that.
2 Likes
I’m not sure exactly what I did that made this go away, but modified my defoverridable
to reference the behavioiur instead of specific callbacks, e.g.
defoverridable MyBehaviour
I also had to clean up my @callbacks
so they included a final argument for a Keyword of opts
… after doing that, the compile warnings disappeared.