Background
I have a project that I have recently converted to run as an OTP application. Upon doing this I came back to the “Elixir in Action” book and replay the same steps - but I found something is wrong in the book.
Code
This is how @sasajuric defines an Application
(I have added typespec for calrity):
defmodule Todo.Application do
use Application
@impl Application
@spec start(any, any) :: Supervisor.on_start
def start(_, _) do
Todo.System.start_link()
end
end
Simple enough. Todo.System
is a simple supervisor:
defmodule Todo.System do
@spec start_link() :: Supervisor.on_start
def start_link do
Supervisor.start_link([...children...], strategy: :one_for_one)
end
end
Problem
At first glance it seems like everything is as it should be. But dialyzer pointed me a problem:
The return type ‘ignore’ in the specification of start/2 is not a subtype of {‘error’,} | {‘ok’,pid()} | {‘ok’,pid(),}, which is the expected return type for the callback of the ‘Elixir.Application’ behaviour(undefined)
This all means that what Todo.System.start_link
returns (Supervisor.on_start
which expands to something similar to{:ok, pid} | :ignore | {:error, any}
) is not compatible with what Todo.Application.start
should return: :ok | {:error, term}
.
Now, I am not sure what consequences this can have in the long term. The apps launch for now, but this may change on latter updates.
Am I missing something?
But maybe I am missing something? Maybe dialyzer is not smart enough to see some hidden compatibility going on and I am just crying wolf for nothing. What do you think? Is my analysis correct?
On the other hand, if this is in fact wrong, it would be nice if the author could issue a fix (perhaps in the 3rd edition )