From 5d41b3bfce72ab583dd3c25c543ffe568a1696c5 Mon Sep 17 00:00:00 2001
From: Hans Bolinder
nonempty_maybe_improper_list(Type) :: nonempty_maybe_improper_list(Type, any()) -nonempty_maybe_improper_list() :: nonempty_maybe_improper_list(any()) -+nonempty_maybe_improper_list() :: nonempty_maybe_improper_list(any())
where the following two types define the set of Erlang terms one would expect:
nonempty_improper_list(Type1, Type2) -nonempty_maybe_improper_list(Type1, Type2) -+nonempty_maybe_improper_list(Type1, Type2)
Also for convenience, we allow for record notation to be used. Records are just shorthands for the corresponding tuples.
Record :: #Erlang_Atom{} - | #Erlang_Atom{Fields} -+ | #Erlang_Atom{Fields}
Records have been extended to possibly contain type information.
This is described in the sub-section
-type my_struct_type() :: Type. --opaque my_opaq_type() :: Type. -+-opaque my_opaq_type() :: Type.
where the type name is an atom (
--type orddict(Key, Val) :: [{Key, Val}]. -+-type orddict(Key, Val) :: [{Key, Val}].
A module can export some types in order 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]). -+-export_type([T1/A1, ..., Tk/Ak]). where the Ti's are atoms (the name of the type) and the Ai's are their arguments. An example is given below:
--export_type([my_struct_type/0, orddict/2]). -+-export_type([my_struct_type/0, orddict/2]). Assuming that these types are exported from module
mod:my_struct_type() -mod:orddict(atom(), term()) -+mod:orddict(atom(), term()) One is not allowed to refer to types which are not declared as exported.
@@ -324,30 +311,25 @@ mod:orddict(atom(), term())
The types of record fields can be specified in the declaration of the
record. The syntax for this is:
For fields without type annotations, their type defaults to any().
I.e., the above is a shorthand for:
In the presence of initial values for fields,
the type must be declared after the initialization as in the following:
Naturally, the initial values for fields should be compatible
with (i.e. a member of) the corresponding types.
@@ -364,8 +346,7 @@ mod:orddict(atom(), term())
-record(rec, {f1 = 42 :: integer(),
f2 :: 'undefined' | float(),
- f3 :: 'undefined' | 'a' | 'b'}).
-
+ f3 :: 'undefined' | 'a' | 'b'}).
For this reason, it is recommended that records contain initializers,
whenever possible.
@@ -375,16 +356,14 @@ mod:orddict(atom(), term())
can be used as a type using the syntax:
In addition, the record fields can be further specified when using
a record type by adding type information about the field in
the following manner:
Any unspecified fields are assumed to have the type in the original
record declaration.
@@ -398,8 +377,7 @@ mod:orddict(atom(), term())
compiler attribute
The arity of the function has to match the number of arguments,
or else a compilation error occurs.
@@ -414,22 +392,19 @@ mod:orddict(atom(), term())
For most uses within a given module, the following shorthand suffices:
Also, for documentation purposes, argument names can be given:
A function specification can be overloaded.
That is, it can have several types, separated by a semicolon (
A current restriction, which currently results in a warning
(OBS: not an error) by the compiler, is that the domains of
@@ -438,8 +413,7 @@ mod:orddict(atom(), term())
Type variables can be used in specifications to specify relations for
the input and output arguments of a function.
@@ -447,20 +421,19 @@ mod:orddict(atom(), term())
polymorphic identity function:
However, note that the above specification does not restrict the input
and output type in any way.
We can constrain these types by guard-like subtype constraints:
+ or equivalently by the more succinct and more modern form of the above:
+
and provide bounded quantification. Currently, the
Some functions in Erlang are not meant to return;
either because they define servers or because they are used to
throw exceptions as the function below:
For such functions we recommend the use of the special no_return()
type for their "return", via a contract of the form:
--record(rec, {field1 :: Type1, field2, field3 :: Type3}).
-
+-record(rec, {field1 :: Type1, field2, field3 :: Type3}).
--record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).
-
+-record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).
--record(rec, {field1 = [] :: Type1, field2, field3 = 42 :: Type3}).
-
+-record(rec, {field1 = [] :: Type1, field2, field3 = 42 :: Type3}).
-#rec{}
-
+#rec{}
-#rec{some_field :: Type}
-
+#rec{some_field :: Type}
--spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType.
-
+-spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType.
--spec Function(ArgType1, ..., ArgTypeN) -> ReturnType.
-
+-spec Function(ArgType1, ..., ArgTypeN) -> ReturnType.
--spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.
-
+-spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.
-spec foo(T1, T2) -> T3
- ; (T4, T5) -> T6.
-
+ ; (T4, T5) -> T6.
-spec foo(pos_integer()) -> pos_integer()
- ; (integer()) -> integer().
-
+ ; (integer()) -> integer().
--spec id(X) -> X.
-
+-spec id(X) -> X.
--spec id(X) -> X when is_subtype(X, tuple()).
-
- or equivalently by the more succint and more modern form of the above:
+-spec id(X) -> X when is_subtype(X, tuple()).
+
--spec id(X) -> X when X :: tuple().
-
+-spec id(X) -> X when X :: tuple().
-spec foo({X, integer()}) -> X when X :: atom()
- ; ([Y]) -> Y when Y :: number().
-
+ ; ([Y]) -> Y when Y :: number().
-my_error(Err) -> erlang:throw({error, Err}).
-
+my_error(Err) -> erlang:throw({error, Err}).
--spec my_error(term()) -> no_return().
-
+-spec my_error(term()) -> no_return().