Specifying a Type
Understand the specific types of Elixir.
We'll cover the following
A type is simply a subset of all possible values in a language. For example, the type integer
means all the possible integer values but excludes lists, binaries, PIDs, and so on.
The basic types in Elixir are as follows:
any
, atom
, float
, fun
, integer
, list
, map
, maybe_improper_list
, none
, pid
, port
, reference
, struct
, and tuple
.
The type any
(and its alias, _
) is the set of all values, and none
is the empty set. A literal atom or integer is the set containing just that value.
The value nil can be represented as nil
.
Collection types
A list is represented as [type]
, where type is any of the basic or combined types. This notation doesn’t signify a list of one element. It simply says that elements of the list will be of the given type. If we want to specify a nonempty list, we use [type, ...]
. As a convenience, the type list
is an alias for [any]
.
Binaries are represented using this syntax:
-
<< >>
specifies an empty binary (size 0). -
<< _ :: size >>
specifies a sequence of size bits. This is called a bitstring. -
<< _ :: size * unit_size >>
specifies a sequence ofsize
units, where each unit isunit_size
bits long.
In the last two instances, size
can be specified as _
, in which case the binary has an arbitrary number of bits/units.
The predefined type bitstring
is equivalent to <<_::_>>
, an arbitrarily sized sequence of bits. Similarly, binary
is defined as <<_::_*8>>
, an arbitrary sequence of 8-bit bytes.
Tuples are represented as { type, type,... }
or by using the type
tuple, so both {atom, integer}
and tuple(atom, integer}
represent a tuple whose first element is an atom and whose second element is an integer.
Combining types
The range operator (..
) can be used with literal integers to create a type representing that range. The three built-in types are as follows:
- The
non_neg_integer
type represents integers that are greater than or equal to zero. - The
pos_integer
type represents integers that are greater than zero. - The
neg_integer
type represents integers that are less than zero.
The union operator (|
) indicates that the acceptable values are the unions of its arguments.
Parentheses may be used to group terms in a type specification.
Structures
As structures are basically maps, we could just use the map
type for them, but doing so throws away a lot of useful information. Instead, we recommend defining a specific type for each struct:
defmodule LineItem do
defstruct sku: "", quantity: 1
@type t :: %LineItem{sku: String.t, quantity: integer}
end
We can then reference this type as LineItem.t
.
Anonymous functions
Anonymous functions are specified using (head -> return_type)
.
The head specifies the arity and possibly the types of the function parameters. We use “...”
to mean an arbitrary number of arbitrarily typed arguments or a list of types, in which case the number of types is the function’s arity.
(... -> integer) # Arbitrary parameters: returns an integer
(list(integer) -> integer) # Takes a list of integers and returns an integer
(() -> String.t) # Takes no parameter and returns an Elixir string
(integer, atom -> list(atom)) # Takes an integer and an atom and returns
# a list of atoms
We can put parentheses around the head if we find it clearer:
( atom, float -> list )
( (atom, float) -> list )
(list(integer) -> integer)
((list(integer)) -> integer)
Handling truthy values
The type as_boolean(T)
says that the actual value matched will be of type T
, but the function that uses the value will treat it as a truthy value (anything other than nil
or false
is considered true). Therefore, the specification for the Elixir function Enum.count
is the following:
@spec count(t, (element -> as_boolean(term))) :: non_neg_integer
Some examples
-
integer | float
specifies any number (Elixir has an alias for this). -
[ {atom, any} ] list(atom, any)
specifies a list of key-value pairs. The two forms are the same. -
non_neg_integer | {:error, String.t}
specifies an integer greater than or equal to zero, or a tuple containing the atom:error
and astring
. -
( integer, atom -> { :pair, atom, integer } )
specifies an anonymous function that takes an integer and an atom and returns a tuple containing theatom :pair
, anatom
, and aninteger
. -
<< _ :: _ * 4 >>
specifies a sequence of 4-bit nibbles.
Get hands-on with 1400+ tech skills courses.