From 57493ef46d92155f0f7223858c4b612b840f485a Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Mon, 6 Sep 2010 19:58:07 +0300 Subject: Up-to-date additions and changes to type reference manual. --- system/doc/reference_manual/typespec.xml | 615 ++++++++++++++++--------------- 1 file changed, 324 insertions(+), 291 deletions(-) (limited to 'system') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 52dc0c943e..981a44642a 100755 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -4,7 +4,7 @@
- 20032009 + 20032010 Ericsson AB. All Rights Reserved. @@ -139,326 +139,359 @@ Tuple :: tuple() %% stands for a tuple of any size TList :: Type | Type, TList ]]> -

- Because lists are commonly used, they have shorthand type notations. - The type list(T) has the shorthand [T]. The shorthand [T,...] stands for - the set of non-empty proper lists whose elements are of type T. - The only difference between the two shorthands is that [T] may be an - empty list but [T,...] may not. -

-

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

-

- 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. (Some type unions below slightly abuse the syntax of types.) -

- - - Built-in typeStands for - - - term()any() - - - bool()'false' | 'true' - - - byte()0..255 - - - char()0..16#10ffff - - - non_neg_integer()0.. - - - pos_integer()1.. - - - neg_integer()..-1 - - - number()integer() | float() - - - list()[any()] - - - maybe_improper_list()maybe_improper_list(any(), any()) - - - maybe_improper_list(T)maybe_improper_list(T, any()) - - - string()[char()] - - - nonempty_string()[char(),...] - - - iolist()maybe_improper_list( -char() | binary() | iolist(), binary() | []) - - - module()atom() - - - mfa(){atom(),atom(),byte()} - - - node()atom() - - - timeout()'infinity' | non_neg_integer() - - - no_return()none() - -
- -

- 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. - (For bootstrapping purposes, it can also result to just a warning if this - involves a built-in type which has just been introduced.) -

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

+ Because lists are commonly used, they have shorthand type notations. + The type list(T) has the shorthand [T]. + The shorthand [T,...] stands for + the set of non-empty proper lists whose elements are of type T. + The only difference between the two shorthands is that [T] may be an + empty list but [T,...] may not. +

+

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

+

+ 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. (Some type unions below slightly abuse the syntax of types.) +

+ + + Built-in typeStands for + + + term()any() + + + bool()'false' | 'true' + + + byte()0..255 + + + char()0..16#10ffff + + + non_neg_integer()0.. + + + pos_integer()1.. + + + neg_integer()..-1 + + + number()integer() | float() + + + list()[any()] + + + maybe_improper_list()maybe_improper_list(any(), any()) + + + maybe_improper_list(T)maybe_improper_list(T, any()) + + + string()[char()] + + + nonempty_string()[char(),...] + + + iolist()maybe_improper_list(char() | binary() | iolist(), binary() | []) + + + module()atom() + + + mfa(){atom(),atom(),byte()} + + + node()atom() + + + timeout()'infinity' | non_neg_integer() + + + no_return()none() + +
+ +

+ 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. + (For bootstrapping purposes, it can also result to just a warning if this + involves a built-in type which has just been introduced.) +

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

- where the following two types - define the set of Erlang terms one would expect: -

-
+  
+

+ 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)
-	
-

- Also for convenience, we allow for record notation to be used. - Records are just shorthands for the corresponding tuples. -

-
+  
+

+ 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}
+  
+

+ Records have been extended to possibly contain type information. + This is described in the sub-section "Type information in record declarations" below. +

+ + +
+ Type declarations of user-defined types +

+ As seen, the basic syntax of a type is an atom followed by closed + parentheses. New types are declared using '-type' and '-opaque' + compiler attributes as in the following: +

+
+-type my_struct_type() :: Type.
+-opaque my_opaq_type() :: Type.
     

- Records have been extended to possibly contain type information. - This is described in the sub-section "Type information in record declarations" below. -

-
- -
- Type declarations of user-defined types -

- As seen, the basic syntax of a type is an atom followed by closed - parentheses. New types are declared using '-type' compiler attributes - as in the following: -

-
--type my_type() :: Type.
-		
-

- where the type name is an atom ('my_type' in the above) followed by - parenthesis. Type is a type as defined in the previous section. - A current restriction is that Type can contain only predefined types - or user-defined types which have been previously defined. - This restriction is enforced by the compiler and results in a - compilation error. (A similar restriction currently exists for records). -

-

- This means that currently general recursive types cannot be defined. - Lifting this restriction is future work. -

-

- Type declarations can also be parameterized by including type variables - between the parentheses. The syntax of type variables is the same as - Erlang variables (starts with an upper case letter). - Naturally, these variables can - and should - appear on the RHS of the - definition. A concrete example appears below: -

-
+      where the type name is an atom ('my_struct_type' in the above)
+      followed by parentheses. Type is a type as defined in the
+      previous section.
+      A current restriction is that Type can contain only predefined types,
+      or user-defined types which are either module-local (i.e., with a
+      definition that is present in the code of the module) or are remote
+      types (i.e., types defined in and exported by other modules; see below).
+      For module-local types, the restriction that their definition
+      exists in the module is enforced by the compiler and results in a
+      compilation error. (A similar restriction currently exists for records.)
+    

+

+ Type declarations can also be parameterized by including type variables + between the parentheses. The syntax of type variables is the same as + Erlang variables (starts with an upper case letter). + Naturally, these variables can - and should - appear on the RHS of the + definition. A concrete example appears below: +

+
 -type orddict(Key, Val) :: [{Key, Val}].
-		
- -
- - -
- - Type information in record declarations - -

- The types of record fields can be specified in the declaration of the - record. The syntax for this is: -

-
+    
+

+ 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]).
+      
+ 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]).
+      
+ Assuming that these types are exported from module 'mod' then + one can refer to them from other modules using remote type expressions + like those below: +
+mod:my_struct_type()
+mod:orddict(atom(), term())
+      
+ One is not allowed to refer to types which are not declared as exported. +

+

+ Types declared as opaque represent sets of terms whose + structure is not supposed to be visible in any way outside of + their defining module (i.e., only the module defining them is + allowed to depend on their term structure). Consequently, such + types do not make much sense as module local - module local + types are anyway not accessible by other modules - and should + always be exported. +

+
+ + +
+ + Type information in record declarations + +

+ The types of record fields can be specified in the declaration of the + record. The syntax for this is: +

+
 -record(rec, {field1 :: Type1, field2, field3 :: Type3}).
-		
-

- For fields without type annotations, their type defaults to any(). - I.e., the above is a shorthand for: -

-
+    
+

+ For fields without type annotations, their type defaults to any(). + I.e., the above is a shorthand for: +

+
 -record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).		
-		
-

- In the presence of initial values for fields, - the type must be declared after the initialization as in the following: -

-
+    
+

+ In the presence of initial values for fields, + the type must be declared after the initialization as in the following: +

+
 -record(rec, {field1 = [] :: Type1, field2, field3 = 42 :: Type3}).
-		
-

- Naturally, the initial values for fields should be compatible - with (i.e. a member of) the corresponding types. - This is checked by the compiler and results in a compilation error - if a violation is detected. For fields without initial values, - the singleton type 'undefined' is added to all declared types. - In other words, the following two record declarations have identical - effects: -

-
+    
+

+ Naturally, the initial values for fields should be compatible + with (i.e. a member of) the corresponding types. + This is checked by the compiler and results in a compilation error + if a violation is detected. For fields without initial values, + the singleton type 'undefined' is added to all declared types. + In other words, the following two record declarations have identical + effects: +

+
 -record(rec, {f1 = 42 :: integer(),
               f2      :: float(),
-              f3      :: 'a' | 'b').
+              f3      :: 'a' | 'b'}).
 
 -record(rec, {f1 = 42 :: integer(),
               f2      :: 'undefined' | float(),
-              f3      :: 'undefined' | 'a' | 'b').
-		
-

- For this reason, it is recommended that records contain initializers, - whenever possible. -

-

- Any record, containing type information or not, once defined, - can be used as a type using the syntax: -

-
+              f3      :: 'undefined' | 'a' | 'b'}).
+    
+

+ For this reason, it is recommended that records contain initializers, + whenever possible. +

+

+ Any record, containing type information or not, once defined, + can be used as a type using the syntax: +

+
 #rec{}
-		
-

- 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: -

-
+    
+

+ 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: +

+
 #rec{some_field :: Type}
-		
-

- Any unspecified fields are assumed to have the type in the original - record declaration. -

-
+
+

+ Any unspecified fields are assumed to have the type in the original + record declaration. +

+ -
- Specifications (contracts) for functions -

- A contract (or specification) for a function is given using the new - compiler attribute '-spec'. The basic format is as follows: -

-
+  
+ Specifications for functions +

+ A specification (or contract) for a function is given using the new + compiler attribute '-spec'. The general format is as follows: +

+
 -spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType.
-		
-

- The arity of the function has to match the number of arguments, - or else a compilation error occurs. -

-

- This form can also be used in header files (.hrl) to declare type - information for exported functions. - Then these header files can be included in files that (implicitly or - explicitly) import these functions. -

-

- For most uses within a given module, the following shorthand is allowed: -

-
+    
+

+ The arity of the function has to match the number of arguments, + or else a compilation error occurs. +

+

+ This form can also be used in header files (.hrl) to declare type + information for exported functions. + Then these header files can be included in files that (implicitly or + explicitly) import these functions. +

+

+ For most uses within a given module, the following shorthand suffices: +

+
 -spec Function(ArgType1, ..., ArgTypeN) -> ReturnType.
-		
-

- Also, for documentation purposes, argument names can be given: -

-
+    
+

+ Also, for documentation purposes, argument names can be given: +

+
 -spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.
-		
-

- A function specification can be overloaded. - That is, it can have several types, separated by a semicolon (;): -

-
+    
+

+ A function specification can be overloaded. + That is, it can have several types, separated by a semicolon (;): +

+
 -spec foo(T1, T2) -> T3
        ; (T4, T5) -> T6.
-       
-

- A current restriction, which currently results in a warning - (OBS: not an error) by the compiler, is that the domains of the argument - types cannot be overlapping. - For example, the following specification results in a warning: -

-
+    
+

+ A current restriction, which currently results in a warning + (OBS: not an error) by the compiler, is that the domains of + the argument types cannot be overlapping. + For example, the following specification results in a warning: +

+
 -spec foo(pos_integer()) -> pos_integer()
        ; (integer()) -> integer().
-       	
-

- Type variables can be used in specifications to specify relations for - the input and output arguments of a function. - For example, the following specification defines the type of a - polymorphic identity function: -

-
+    
+

+ Type variables can be used in specifications to specify relations for + the input and output arguments of a function. + For example, the following specification defines the type of a + polymorphic identity function: +

+
 -spec id(X) -> X.
-		
-

- 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: -

-
+    
+

+ 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: +

+
 -spec id(X) -> X when is_subtype(X, tuple()).
-		
-

- and provide bounded quantification. Currently, - the is_subtype/2 guard is the only guard which can - be used in a '-spec' attribute. -

-

- The scope of an is_subtype/2 constraint is the - (...) -> RetType - specification after which it appears. To avoid confusion, - we suggest that different variables are used in different constituents of - an overloaded contract as in the example below: -

-
--spec foo({X, integer()}) -> X when is_subtype(X, atom())
-       ; ([Y]) -> Y when is_subtype(Y, number()).
-		
-

- 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: -

-
+    
+ or equivalently by the more succint and more modern form of the above: +
+-spec id(X) -> X when X :: tuple().
+    
+

+ and provide bounded quantification. Currently, the :: constraint + (the is_subtype/2 guard) is the only guard constraint which can + be used in the 'when' part of a '-spec' attribute. +

+

+ The scope of an :: constraint is the + (...) -> RetType + specification after which it appears. To avoid confusion, + we suggest that different variables are used in different + constituents of an overloaded contract as in the example below: +

+
+-spec foo({X, integer()}) -> X when X :: atom()
+       ; ([Y]) -> Y when Y :: number().
+    
+

+ 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: +

+
 my_error(Err) -> erlang:throw({error, Err}).
-		
-

- For such functions we recommend the use of the special no_return() - type for their "return", via a contract of the form: -

-
+    
+

+ For such functions we recommend the use of the special no_return() + type for their "return", via a contract of the form: +

+
 -spec my_error(term()) -> no_return().
-		
-
+
+
-- cgit v1.2.3