How to use typespecs and dialyzer with behavior?

In Elixir, how can I document that a function will return a module that implements a specific behavior?

To use a trivial example, let's say I created a GreeterBehaviour behavior that is implemented by two modules:

 defmodule GreeterBehaviour do @callback say_hello(String.t) :: String.t end defmodule FormalGreeter do @behaviour GreeterBehaviour def say_hello(name) do "Good day to you #{name}" end end defmodule CasualGreeter do @behaviour GreeterBehaviour def say_hello(name) do "Hey #{name}" end end 

Then I want to easily change any of these implementations, getting Greeter through a function:

 defmodule MyApp do def main do greeter().say_hello("Pete") |> IO.puts end @spec greeter() :: GreeterBehaviour # This doesn't work with dialyzer def greeter do FormalGreeter # Can easily be swapped to CasualGreeter end end 

Dialyzer will successfully verify that both CasualGreeter and FormalGreeter correctly implement GreeterBehaviour behavior. However, how can I define typepec so that Dialyzer checks that greeter/0 returns a module that actually implements GreeterBehaviour ?

Using @spec greeter() :: GreeterBehaviour does not work, as Dialyzer will give a warning:

 lib/my_app.ex:19: Invalid type specification for function 'Elixir.MyApp':greeter/0. The success typing is () -> 'Elixir.FormalGreeter' 
+10
source share

Source: https://habr.com/ru/post/1269167/


All Articles