By Limin Fu. Released under the GNU Free Documentation License. 

Data Types and Type Annotation


Dao supports optional/hybrid typing that allows variables to be declared with or without
type annotations. When a variable is declared without type annotation, its type will be a
utomatically inferred at compiling time based on some type dedcution rules if possible. I
f a variable has an explicit type annotation or a successfully inferred type, static type
checking will be carried out on this variable at compiling time, otherwise, it will be ch
ecked at running time.

 1  Type Annotation    
 1  Type Annotation    
 1  Type Annotation    

Type annotations in Dao are usually placed after the variable, parameter or field names w
ith a colon separating the names and the annotation. 
   1  var name: type
   2  var name: type = value
   4  routine MyFunction( name: string, index: int = 1 ) { ... }
   6  class Klass
   7  {
   8      var name: type = value
   9  }

Multiple variables can be declared at once with the same type and initial value: 
   1  var name1, name2 : type
   2  var name1, name2 : type = value

 2  Data Types    
 2  Data Types    
 2  Data Types    

Dao supports a rich set of types to allow writing expressive codes.

 2.1  Basic Types 

The basic types are the following:
  Type Name  Type Description                   
  none       none value type                    
  bool       boolean type                       
  int        64 bit integer type                
  float      64 bit floating point number type  
  complex    complex number type                
  string     string type                        
  enum       enum symbol type                   
Though enum is a basic type, its type names may vary and include symbol names that are as
sociated with the enum types. Examples, 
   1  var name: string
   2  var state: enum<off,on> = $on

 2.2  Aggregated Types 

The essential aggregated types in Dao are the followings:
  Type Name                        Type Description  
  array < ElementType >            array type        
  tuple < ItemTypesOrNamesTypes >  tuple type        
  list  < ItemType >               list type         
  map   < KeyType, ValueType >     map type          
These are template-like types that can take type arguments. The type arguments usually in
dicate what types of values the aggregated types may contain. For example, 
   1  array<int>         # Array that may contain integers;
   2  list<string>       # List that may contain strings;
   3  map<string,int>    # Map that may contain pairs of string and int;
   4  tuple<string,int>  # Tuple that may contain one string and one integer;
   6  # The following is a tuple type with named items:
   7  # The first item is named "name" and has type "string";
   8  # The second item is named "index" and has type "int";
   9  tuple<name:string,index:int>

Examples of type annotations with these types, 
   1  var vector: array<int> = [ 1, 2, 3 ]
   2  var tuple1: tuple<string,int> = ( "abc", 123 )
   3  var tuple2: tuple<name:string,index:int> = ( 'abc', 123 )
   4  var names:  list<string> = { "Joe" }
   5  var table:  map<string,int> = { "abc" => 123 }

 2.3  Type Holder Types 

Type holder types are type names with a @ prefix. They represent to-be-defined types, the
same type holder represents the same type within a local context (a single composite type
or a function prototype etc). They are usually used in template-like types as place holde
rs for type arguments, and in the routine signatures of the methods of those types. This 
way, both the types and their methods are made generic, and can be instantiated (speciali
zed) for particular argument types.

For example, the list template type is declared as list<@T=any>, where any is the default
argument type for the list type. This means list<> will be equivalent to list<any>. One o
f the list methods is the following, 
   1  append( self: list<@T>, item: @T, ... : @T ) => list<@T>
Within this routine signature, all @T represent the same type. So this method means, for 
a list of type list<@T> (@T is string for example), only items of type @T (string) can be
appended to the list.

Here is a simpler example, 
   1  tuple<@T,@T>
represents a tuple type whose two items must have the same type.

 2.4  Any Type 

Special type any cab be used to represent any type. Declaring a variable with any type wi
ll effectively disable compiling time type checking on the variable!

 2.5  Value Type 

Another special type in Dao is the value type, which, in addition to define type traits a
nd information like the ordinary types, also defines a constant value. When a value or an
other value type is checked against a value type, not only the types should match, but al
so the values as well.

The none is supported as a value type, it is designed this mainly because, none only has 
one unique value. The none can be used any where like an ordinary type, but it is mostly 
used in variant types to indicate a variable or parameter may also hold a none value (see
the next subsection).

Other value types cannot be used every where like ordinary types, they mainly appear as t
ype arguments in composite types. For example, 
   1  tuple<1,2>
represents a tuple type whose first item must be 1 and its second must be 2! Such value t
ypes are mainly useful when dealing with C++ template types.

 2.6  Variant Type 

A variant type is a type that can represent multiple alternative types. A variant type is
declared by joining these alternative types using  | as the delimiter. A variable of a va
riant type can hold value of any of the alternative types. For example, 
   1  var intstr : int|string = 123
   2  intstr = 'abc'

In Dao, only variables of none type or unspecific types such as any and undefined type ho
lder types can hold none value. But some times, some variables may need to or be known to
hold either a none value or a value of a specific type, to allow this in the type checkin
g, one needs use some_type|none for these variables. For example, 
   1  routine FindWord( source: string, word: string ) => int|none
   2  {
   3      var pos = source.find( word )
   4      if( pos < 0 ) return none
   5      return pos
   6  }
   8  var pos1 = FindWord( "dao language", "dao" )  # pos1 = 0
   9  var pos2 = FindWord( "dao language", "lua" )  # pos2 = none
Please see dao.type.variant for more information.

 2.7  Routine (Function) Types 

Routine (function) types are composed of keyword routine with other types, they are usual
ly automatically generated for routines from their declarations. For example, 
   1  routine Test( name: string, value = 123 )
   2  {
   3      return value * 10;
   4  }
   5  io.writeln( std.about(Test) )
   6  # Output: Test{routine<name:string,value=int=>int>}[0x7f9ef1c50340]
In the output routine<name:string,value=int=>int> is the automatically created type for t
he routine Test. Here, 
  *  name:string : type information for the first parameter; it means the first parameter
     is named name and has type string.
  *  value=int : type information for the second parameter; it means that the second para
     meter is named value, and it has type int and a defualt parameter value;
  *  =>int : (inferred) type information for the returned value; 

For code section routines, their type names have additional parts. For example, one of th
e list sorting method is a code section method with the following signature (prototype), 
   1  sort( self: list<@T>, part = 0 )[X: @T, Y: @T => int] => list<@T>
Its type name is, 
   1  routine<self:list<@T>,part=int=>list<@T>>[X:@T,Y:@T=>int]
Here [X:@T,Y:@T=>int] is the additional part with respect to types for normal routines, a
nd means that the code section may take two parameters of type @T and is expected produce
an integer from evaluating the code section.

Of course, the routine types can also be declared explicitly. So one can annotation a var
iable with the following routine type name: 
   1  var myfunc: routine<p1:string,p2=int=>int>

 2.8  Generic Types 

The standard aggregated types such as list and maps etc. in Dao are supported as builtin 
generic types. Such support is also extended to user defined types, but such generic type
s can only be defined in C modules. The use of such types is exactly the same way as the 
standard generic types.

One typical example for such generic types is the future value type mt::future<@V>. Thoug
h future is a builtin type, user can define customized types in exactly the same way as d
efining future. Please see  daovm.interface.extending for the techniques of defining such

 2.9  Type Aliasing 

Type alias can be defined using the following syntax:
   1  #TypeAliasing ::= 'type' Identifier '=' Type
   2  type alias = another_type
For example, 
   1  type StringList = list<string>
   2  type Point3D    = tuple<x:float,y:float,z:float>


dao.type--| dao.type: Data Types and Type Annotation (77.5 KB)
          |--bool-----| dao.type.bool: Boolean Type (0.3 KB)
          |--int------| Integer Type (0.6 KB)
          |--float----| dao.type.float: Float Type (0.6 KB)
          |--complex--| dao.type.complex: Complex Type (0.6 KB)
          |--enum-----| dao.type.enum: Enum or Symbol Type (5.1 KB)
          |--string---| dao.type.string: String Type (25.4 KB)
          |           |--pattern--| dao.type.string.pattern: String Pattern Matching (11.8 KB)
          |           |--method---| dao.type.string.method: Dao string methods (11.1 KB)
          |--array----| dao.type.array: Numeric Array Type (8.7 KB)
          |           |--method--| dao.type.array.method: Array methods (6.7 KB)
          |--list-----| dao.type.list: List Container Type (13.9 KB)
          |           |--method--| dao.type.list.method: List Methods (13.0 KB)
          |--map------| Map or Hash Map Container Type (7.5 KB)
          |           |--method--| Map Methods (6.0 KB)
          |--tuple----| dao.type.tuple: Tuple Type (1.5 KB)
          |--variant--| dao.type.variant: Variant (Disjoint Union) Type (3.3 KB)