I’ve been having a small block in continuing my series on Elixir application design. So this week I’ve written about another topic which has been sitting on my Learning Elixir TODO list for some time: type checking. This topic has been on my mind lately because I have been looking at the language PureScript which is similar to Haskell and centered around its type system. I’d like to see how Elixir’s type specs compare.
In this post I’ll go back and run Dialyzer on the Game of Life implementation that I used in my Optmizing Elixir series. I’ll also work with Elixir’s type annotations to make the types in the source more explicit.
I’ve opted to use Dialyxir to simplify use of Dialyzer in my project. I followed the directions from the README.
Building the PLT took about 5-6 minutes on my system. This step builds the Persistent Lookup Table which contains type information for the standard library. This way Dialyzer doesn’t have to analyze the standard library every time I run it.
Next I went back to my Game of Life source and ran Dialyzer:
@jeremyjh wasn’t kidding, Dialyxir really makes this process easy.
Interpreting Dialyzer Results
The next step is to read over the Dialyzer output and understand what it means. I’ll start with
lifebench.ex:58: Function usage/0 only terminates with explicit exception
My function doesn’t terminate? Oh, right it doesn’t really:
This usage function is part of the
lifebench mix task. My next thought was “how does dialyzer know?” and the answer must be in the type of
Kernel.exit/1. Looking up the documentation for
Kernel.exit/1 I found in its specs:
So I add something similar to
lifebench.usage/0 like this:
and with this change Dialyzer is happy with
By the way, after making the change I have to recompile and then run dialyzer. I can do this in one
mix invocation like this:
LifebenchCmp.usage/0 still has the same problem:
and the same solution works here too.
The remaining errors
Come from external modules. I certainly don’t want to see these warnings all the time so I should either include these in the analysis or supress them.
I had limited success adding modules for dialyzer in mix.exs
This reduces the Dialyzer errors down to:
eprof and fprof are part of the erlang standard library so I would have expected them in my PLT but they were not included. ExPrintf has too many warnings of its own so I left it out.
The next step for me would be to go back into the Game of Life source and start adding type specs to make sure I really understand the funcitons I have. As I go I would have dialyzer at my side to make sure I’m building something type-consistent.
I think I will continue with this in next week’s post.