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

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
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
Phillipp
Hey, I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
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
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
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
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

We're in Beta

About us Mission Statement