Dializer
Dialyzer is a static analysis tool that identifies software discrepancies, such as definite type errors, code that is unreachable because of programming errors, and unnecessary tests in Erlang and Elixir modules or an entire codebases.
Erlang Type Notation
We can define a subset of Erlang types as follows:
Type :: any() | none() | pid() | port() | reference() | [] | Atom | binary() | float() | Fun | Integer | [Type] | Tuple | Union | UserDefined Union :: Type1 | Type2 | ... Atom :: atom() | Erlang_Atom Integer :: integer() | Min .. Max Fun :: fun() | fun((...) -> Type) Tuple :: tuple() | {T1, T2, ... Tn}
New types can be defined with the following syntax:
-type NewTypeName(TVar1, TVar2, ... , TVarN) :: Type.
Specifying the Input and Output Types of a Function
-spec file:open(FileName, Modes) -> {ok, Handle} | {error, Why} when FileName :: string(), Modes :: [Mode], Mode :: read | write | ... Handle :: file_handle(), Why :: error_term().
Exporting Types
A module can export some types to declare that other modules are allowed to refer to them as remote types. This declaration has the following form:
-export_type([T1/A1, ..., Tk/Ak]).
Opaque Types
The main use case for opacity in Erlang is to hide the implementation of a data type, enabling evolving the API while minimizing the risk of breaking consumers.
Running Dializer
Things that confuse Dializer
The dialyzer can get easily confused. We can help prevent this by following a few simple rules. (Armstrong 2013, 151).
- Avoid using
-compile(export_all)
. - Provide detailed type specifications for all the arguments to the exported functions in the module.
- Provide default arguments to all elements in a record definition. If you don't
provide a default, the atom
undefined
is taken as the default. - Using anonymous variables in arguments to a function often results in types that are far less specific than you had intended; try to constrain variables as much as possible.