Elixir - Why are type specs required in a @callback definition?
Asked Answered
D

2

6

It seems like when you define a behaviour you have to include type specs within the @callback definition. Then when you adopt the behaviour, the compiler requires that the function_name/arity is defined, but is perfectly happy if you don't follow the type specs.

My questions are:

  1. Are those observations correct?
  2. If yes, why does @callback couple type specs with the actual functionality of checking that the function_name/arity is defined? It makes it difficult to understand what is documentation and what is core functionality. The rest of Elixir seems to clearly separate the two, keeping type specs as an optional addition.

For example:

If we omit the type specs, we get a compile error

defmodule Greeting do
  @callback hello(person)
end
# (CompileError) iex:82: type specification missing return type: hello(person)

To make the compiler happy, we have to include type specs:

defmodule Greeting do
  @callback hello(%Person{}) :: {:ok, String.t} | {:error, String.t}
end

Now when we adopt the behaviour, the compiler checks that function_name/arity is defined:

defmodule WesternGreeting do
  @behaviour Greeting
  def hello(), do: "Howdy"
end
# warning: undefined behaviour function hello/1 (for behaviour Greeting)

However all the type specs in the @callback are disregarded by the compiler:

defmodule WesternGreeting2 do
  @behaviour Greeting
  def hello([a, b, c]), do: a <> b <> c
end
# No warnings or errors
Db answered 21/2, 2018 at 6:16 Comment(2)
Specs are not checked by the compiler, but by external tools like dialyzerVa
@Va the error in his post says # (CompileError) iex:82: type specification missing return type: hello(person) That seems to suggest it's indeed checked by the compiler. Am I missing something?Hysteric
B
1

In older versions of erlang, it was not required. Somewhere along the line (I don't recall exactly when), it was realized that if you add them it then Dialyzer could do some additional validation.

In addition, you can actually get the types from a module at runtime which has some uses.

https://www.youtube.com/watch?v=7lT4_E6dooQ

Bridal answered 20/5, 2019 at 7:23 Comment(0)
C
0

It's cause @callback is same as @spec, it expects types. If you will define return type in first example, it will fail too:

iex(1)> defmodule Greeting do
...(1)>   @callback hello(person) :: any()
...(1)> end
** (CompileError) iex:2: type person() undefined

About checking types, I suppose it is not done yet

Counterpoison answered 26/2, 2018 at 19:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.