bmitc

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.

@impl docs.

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

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

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. :slight_smile: (The check, to be clear, prevents the use of @impl true.)

kip

kip

ex_cldr Core Team

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

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

bmitc

  1. 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.

  2. When using @impl true, my understanding is that the compiler only checks that the function implements a callback defined in any behaviour that is used. 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 true but 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.

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New

Other popular topics Top

belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New

We're in Beta

About us Mission Statement