7.2 Types and their Syntax

Types describe sets of Erlang terms. Types consist of, and are built from, a set of predefined types, for example, integer(), atom(), and pid(). Predefined types represent a typically infinite set of Erlang terms that belong to this type. For example, the type atom() denotes the set of all Erlang atoms.

For integers and atoms, it is allowed for singleton types; for example, the integers -1 and 42, or the atoms 'foo' and 'bar'. All other types are built using unions of either predefined types or singleton types. In a type union between a type and one of its subtypes, the subtype is absorbed by the supertype. Thus, the union is then treated as if the subtype was not a constituent of the union. For example, the type union:

  1. atom() | 'bar' | integer() | 42

describes the same set of terms as the type union:

  1. atom() | integer()

Because of subtype relations that exist between types, types form a lattice where the top-most element, any(), denotes the set of all Erlang terms and the bottom-most element, none(), denotes the empty set of terms.

The set of predefined types and the syntax for types follows:

  1. Type :: any() %% The top type, the set of all Erlang terms
  2. | none() %% The bottom type, contains no terms
  3. | pid()
  4. | port()
  5. | reference()
  6. | [] %% nil
  7. | Atom
  8. | Bitstring
  9. | float()
  10. | Fun
  11. | Integer
  12. | List
  13. | Map
  14. | Tuple
  15. | Union
  16. | UserDefined %% described in Type Declarations of User-Defined Types
  17.  
  18. Atom :: atom()
  19. | Erlang_Atom %% 'foo', 'bar', ...
  20.  
  21. Bitstring :: <<>>
  22. | <<_:M>> %% M is an Integer_Value that evaluates to a positive integer
  23. | <<_:_*N>> %% N is an Integer_Value that evaluates to a positive integer
  24. | <<_:M, _:_*N>>
  25.  
  26. Fun :: fun() %% any function
  27. | fun((...) -> Type) %% any arity, returning Type
  28. | fun(() -> Type)
  29. | fun((TList) -> Type)
  30.  
  31. Integer :: integer()
  32. | Integer_Value
  33. | Integer_Value..Integer_Value %% specifies an integer range
  34.  
  35. Integer_Value :: Erlang_Integer %% ..., -1, 0, 1, ... 42 ...
  36. | Erlang_Character %% $a, $b ...
  37. | Integer_Value BinaryOp Integer_Value
  38. | UnaryOp Integer_Value
  39.  
  40. BinaryOp :: '*' | 'div' | 'rem' | 'band' | '+' | '-' | 'bor' | 'bxor' | 'bsl' | 'bsr'
  41.  
  42. UnaryOp :: '+' | '-' | 'bnot'
  43.  
  44. List :: list(Type) %% Proper list ([]-terminated)
  45. | maybe_improper_list(Type1, Type2) %% Type1=contents, Type2=termination
  46. | nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above
  47. | nonempty_list(Type) %% Proper non-empty list
  48.  
  49. Map :: #{} %% denotes the empty map
  50. | #{AssociationList}
  51.  
  52. Tuple :: tuple() %% denotes a tuple of any size
  53. | {}
  54. | {TList}
  55.  
  56. AssociationList :: Association
  57. | Association, AssociationList
  58.  
  59. Association :: Type := Type %% denotes a mandatory association
  60. | Type => Type %% denotes an optional association
  61.  
  62. TList :: Type
  63. | Type, TList
  64.  
  65. Union :: Type1 | Type2

Integer values are either integer or character literals or expressions consisting of possibily nested unary or binary operations that evaluate to an integer. Such expressions can also be used in bit strings and ranges.

The general form of bit strings is <<:M, :N>>, where M and N must evaluate to positive integers. It denotes a bit string that is M + (kN) bits long (that is, a bit string that starts with M bits and continues with k segments of N bits each, where k is also a positive integer). The notations <<:*N>>, <<:M>>, and <<>> are convenient shorthands for the cases that M or N, or both, are zero.

Because lists are commonly used, they have shorthand type notations. The types list(T) and nonempty_list(T) have the shorthands [T] and [T,…], respectively. The only difference between the two shorthands is that [T] can be an empty list but [T,…] cannot.

Notice that the shorthand for list(), that is, the list of elements of unknown type, is [_] (or [any()]), not []. The notation [] specifies the singleton type for the empty list.

The general form of map types is #{AssociationList}. The key types in AssociationList are allowed to overlap, and if they do, the leftmost association takes precedence. A map association has a key in AssociationList if it belongs to this type. AssociationList can contain both mandatory (:=) and optional (=>) association types. If an association type is mandatory, an association with that type needs to be present. In the case of an optional association type it is not required for the key type to be present.

The notation #{} specifies the singleton type for the empty map. Note that this notation is not a shorthand for the map() type.

For convenience, the following types are also built-in. They can be thought as predefined aliases for the type unions also shown in the table.

Built-in typeDefined as
term()any()
binary()<<:8>>
bitstring()<<:1>>
boolean()'false' | 'true'
byte()0..255
char()0..16#10ffff
nil()[]
number()integer() | float()
list()[any()]
maybe_improper_list()maybe_improper_list(any(), any())
nonempty_list()nonempty_list(any())
string()[char()]
nonempty_string()[char(),…]
iodata()iolist() | binary()
iolist()maybe_improper_list(byte() | binary() | iolist(), binary() | [])
map()#{any() => any()}
function()fun()
module()atom()
mfa(){module(),atom(),arity()}
arity()0..255
identifier()pid() | port() | reference()
node()atom()
timeout()'infinity' | non_neg_integer()
no_return()none()

Table 7.1: Built-in types, predefined aliases

In addition, the following three built-in types exist and can be thought as defined below, though strictly their "type definition" is not valid syntax according to the type language defined above.

Built-in type Can be thought defined by the syntax
non_neg_integer()0..
pos_integer()1..
neg_integer()..-1

Table 7.2: Additional built-in types

Users are not allowed to define types with the same names as the predefined or built-in ones. This is checked by the compiler and its violation results in a compilation error.

Note

The following built-in list types also exist, but they are expected to be rarely used. Hence, they have long names:

  1. nonempty_maybe_improper_list() :: nonempty_maybe_improper_list(any(), any())
  2. nonempty_improper_list(Type1, Type2)
  3. nonempty_maybe_improper_list(Type1, Type2)

where the last two types define the set of Erlang terms one would expect.

Also for convenience, record notation is allowed to be used. Records are shorthands for the corresponding tuples:

  1. Record :: #Erlang_Atom{}
  2. | #Erlang_Atom{Fields}

Records are extended to possibly contain type information. This is described in Type Information in Record Declarations.