bmitc
What are the benefits, if any, of `@impl true` over `@impl <behaviour>`?
The question in the subject line is pretty self-explanatory, and I’m trying to understand perhaps a hidden misunderstanding. My understanding is that @impl true tells that compiler that the function below it implements a behaviour and will thus check so. Then the behavior of @impl <behaviour> is the same except it additionally checks that the name of the function below it implements a callback of the same name defined by <behaviour>. The documentation also states that false may be passed to @impl, but it does not state what @impl false does. So, I’m not sure what it does do.
In my experience, Elixir developers tend to only use @impl true, but I honestly cannot understand why. With only a few more characters in most cases, you get an additional check and additional clarity, both in single behaviour and multiple behaviour uses. So, I’m both confused why @impl true is in the language and why developers use it.
So, what are the benefits, if any, of @impl true over @impl <behaviour>? Why should one not always use @impl <behaviour>?
Most Liked
Marcus
I think @impl true was added for convenience. For cases where it is clear which behaviour is used.
For example:
defmodule MyAppError do
defexception [:message]
@impl true
def exception(value) do
msg = "did not get what was expected, got: #{inspect(value)}"
%MyAppError{message: msg}
end
end
In my opinion it is a good idea to use @impl <behaviour. Someone with the same opinion has also written a credo check for it.
bmitc
It doesn’t seem like I have any technical misunderstanding then.
@impl true only saves five characters in the most common case of GenServer, so I in general question its convenience and utility. Even in the case of a single behaviour being used, I also don’t like having to scroll up to the use section to see what behaviour is being implemented. And if one comes back later and implements a second behaviour, then one needs to (“need to” as in “should”) go back and replace all the @impl true instances. So in general, it is actually less convenient and requires more work.
In the example of the Exception behaviour, the exact name of the module isn’t clear unless one knows the module already (I had to look it up to be sure).
And yes, I certainly already enforce Credo.Check.Readability.ImplTrue.
(The check, to be clear, prevents the use of @impl true.)
kip
I’m a guilty party for using @impl true in older code. I think at that’s how @impl was documented at the time. These days, yes, definitely should be @impl BehaviourModule.
I believe evaluation of @impl follows the normal Elixir rules: everything except nil and false are “truthy”. I think its only more recent Elixir releases that validate the module as being a behaviour and then checking valid callbacks.
c4710n
In one word, @impl true is a shortcut of @impl <behaviour> when the behaviour implemented by the function is unambiguous.
@impl true just helps you to type less, no other benefits. (in my opinion)
Edit: read @bmitc 's reply, too.
If your module only implements one behaviour, then use @impl true is fine, because the behaviour you are implementing is explicit. For example:
defmodule Demo do
use GenServer # it contains `@behaviour GenServer`, checkout https://github.com/elixir-lang/elixir/blob/d4d0523a1278ba2cc5a59023dcf54659fb458873/lib/elixir/lib/gen_server.ex#L749
@impl true
def handle_call ...
end
When your module implements multiple behaviours, it’s better to use explicit name. Or, it will make other developers confused.
defmodule Demo do
@behaviour B1
@behaviour B2
@impl B1
def fn1 ...
@impl B2
def fn2 ...
end
bmitc
-
It’s not necessarily about communicating with the compiler. It’s about providing clarity for your future self and other developers in the code about what callback is being implemented and from what behaviour.
-
When using
@impl true, my understanding is that the compiler only checks that the function implements a callback defined in any behaviour that isused. Thus, the compiler actually does do an extra check when using@impl <behaviour>in that it checks that that specific behaviour defines the implemented callback. So the compiler may know something with@impl truebut it doesn’t enforce it. And what about the cases where behaviours have similar or the same callbacks defined?
Certainly @impl <behaviour> provides all the expected behavior a extra clarity at zero extra cost.







