[NAME]
ALL.dao.tutorial.routine

[TITLE]
Routine and Decorator

[DESCRIPTION]

Routine is a relative independent block of codes that can be reused by invoking it at 
places where it is needed. It can accept parameters to changes its behaviour. It may also
return results to its caller.

 0.1   Definition  

Dao routines are declared with keyword routine (or function or sub, which are exactly 
equivalent to routine). For example, 
     
   1  routine func( a, b )
   2  {
   3     a += 10;
   4     b += "test";
   5     return a, b; # return more than one results.
   6  }
   7  
   8  ( r1, r2 ) = func( 111, "AAA" );
   9  r3 = func( r1, r2 );
     
defines a function that can take two parameters as input, and return two values as
output.

 0.2  Named Parameter 

In Dao the function parameters are named, and parameter values can be passed in by name:
     
   1  func( b => 123, a => "ABC" );
     


 0.3  Parameter Type and Default Value 

It is also possible to specify the type and/or the default value of a parameter.
     
   1  routine MyRout( name : string, index = 0 )
   2  {
   3     io.writeln( "NAME  = ", name )
   4     io.writeln( "INDEX = ", index )
   5  }
     
Here name is specified as string, and index is specified as an integer with default 
value 0. Any parameter after a parameter with default value must have default values as
well. If a routine is called with wrong type of parameters, or no value is passed to a
parameter without a default value, an exception will be raised and the execution will
abort.

 0.4  Routine Overloading 

Routine overloading by parameter types is also supported in Dao, which means that
multiple routines can be defined with the same name, but different parameter signatures.
     
   1  routine MyRout( index : int, name = "ABC" )
   2  {
   3     io.writeln( "INDEX = ", index )
   4     io.writeln( "NAME  = ", name )
   5  }
   6  
   7  MyRout( "DAO", 123 ) # invoke the first MyRout()
   8  MyRout( 456, "script" ) # invoke the second MyRout()
     


 0.5  Routine As First Class Object 

Dao also support first class functions / routines. They can be created as anonymous
function or closure, in the following way:
     
   1  foo = routine( x, y : TYPE, z = DEFAULT )
   2  {
   3     codes;
   4  }
     
The syntax is nearly identical to the definition of a normal function, except the
following differences:
  1. There is no need for a function name;
  2. The expressions for default parameters do not need to be constant expressions,they 
     are evaluated at running time when the function/closure is created;
  3. The function body may contain variables defined in the "upper" function that creates
     it; depending on the type of the "upper" variable, its copy (for simple types) or
     reference will be used by the created function.

When such function accesses local variables from its outer/upper scope, it is created as
a closure, otherwise as an anonymous function.

Here is a simple example,
     
   1  a = "ABC";
   2  
   3  rout = routine( x, y : string, z = a+a ){
   4      a += "_abc";
   5      io.writeln( "lambda ", a )
   6      io.writeln( "lambda ", y )
   7      io.writeln( "lambda ", z )
   8  }
   9  
  10  rout( 1, "XXX" );
     


 0.6   Coroutine and Generator  

See module.core.coroutine.

 0.7   Code Section Methods  

Code section/block method is an alternative to functional methods in other languages such
as Python. Dao code section is syntactically very similar to the code block in Ruby.
Unlike Ruby code blocks which are compiled as closure and passed as parameter (so it's
essentially a syntax sugar), Dao code section is really a code section in its host
function, no closure is created a runtime. When needed, the method locate the code
section in the host function and run that section of codes.

To define a code section method, it will be necessary to specify two set of parameters
and return types: one for the normal routine, and the other for the code section.
     
   1  routine meth_name( meth_params ) [sect_params => sect_return] => meth_return
   2  {
   3      ...
   4  }
     
The parameter list signature sect_params for the code section specifies what kind of 
parameters this method will pass to the code section; and the section return type 
sect_return indicates what type of value this method expects the code section to return.

Code section method can be called in the following way:
     
   1  returned = meth_name( meth_params ) {
   2      code_block
   3  }
     
If there is no method parameter, it can be simply written as:
     
   1  returned = meth_name {
   2      code_block
   3  }
     
By default, the code section receives the parameters passed in by the method through
implicitly defined variables named X and Y. User can choose to use more meaningful names
by,
     
   1  returned = meth_name { [index, item]
   2      code_block
   3  }
     


For example, list type has a code section method for sorting with the following
signature,
     
   1  sort( self :list<@T>, k=0 ) [X :@T, Y :@T => int] => list<@T>
     
Here the code section parameters X and Y are used to pass two items of the list for 
comparison. The code section return type int indicates that the code section is expected
to return an integer as the comparison result. So this sort() can be use in the 
following ways,
     
   1  numlist = { 11, 44, 21, 32, 56, 67, 25 }
   2  
   3  # Sort all by ascend order:
   4  numlist.sort { X < Y }
   5  
   6  # Sort by descend order until the largest 3 items are sorted:
   7  numlist.sort( 3 ) { X > Y }
   8  # Now the first 3 items of the list is the largest 3 items;
   9  
  10  tuplist = { ( 2, 'ghi' ), ( 1, 'def' ), ( 2, 'abc' ), ( 1, 'abc' ) }
  11  tuplist.sort {
  12      # First sort by the first items of the tuples;
  13      if( X[0] != Y[0] ) return X[0] < Y[0];
  14      # Then sort by the second items;
  15      return X[1] < Y[1];
  16  }
     


In a user defined code section method, the yield statement can be used to pass 
parameters and invoke the execution of the code section that is attached to the call.
Here is an example for user defined code section method,
     
   1  # A function that can be called with a code section.
   2  # The code section is expected to take an integer as parameter,
   3  # and return a string.
   4  routine Test() [X :int => string] => string
   5  {
   6      io.writeln( 'In functional method!' );
   7      s = yield( 123 ); # execute the code section;
   8      io.writeln( 'Yielded value:', s );
   9      return s;
  10  }
  11  
  12  Test {
  13      io.writeln( 'In code section:', X );
  14      return 'abc';
  15  }
     


 0.8   Decorator  

Note: this feature is only functional in the online demos and the latest devel release. 

Decorators are a special type of functions that can be used to modify (decorate) other
functions or create modified versions of these functions. There are two main ways to
decorate a function: one is to specify one or more decorators for a function at its
definition; the other is to call a decorator in an expression in the same way to call a
function. Decorating a function at its definition will change that function, and
decorating a function in an expression will create a modified copy of the function.

A decorator can be defined in almost identical way as definition a normal function with a
few exceptions. First, a decorator must be declared with a name prefixed with @, and 
second, the first parameter must be a routine type, which determines which type of
routines can be decorated by this decorator. A variable to hold the parameters that will
be passed to the function, must also be declared inside a pair of brackets right after
the name of the first parameter.

For example,
     
   1  routine @Decorator( func(args) : routine, extra = 123 )
   2  {
   3      io.writeln( 'Calling function:', std.about( func ), extra );
   4      return func( args, ... ); # ... for parameter expanding;
   5  }
     
This decorator can be applied to any function. In this decorator, the decorated function 
is called with args, which is expanded for the call as indicated by .... args is a 
specially declared variable to hold the parameters that will be passed to the function.

In the following example, the function is decorated and modified at its definition,
     
   1  # brackets can be omitted when the decorator take no parameter:
   2  @Decorator
   3  @Decorator( 456 )
   4  routine Function()
   5  {
   6      io.writeln( 'Function()' )
   7  }
     

While in this one, a modified copy of the function will be returned,
     
   1  routine Function()
   2  {
   3      io.writeln( 'Function()' )
   4  }
   5  func = @Decorator( Function )
     

If a decorator expression uses only constants, the decoration can be done at compiling
time,
     
   1  const MyFunc = @Decorator( Function )
     

This feature can be exploited to create modified copies of existing functions that are
imported or loaded from other modules, and use the same function names,
     
   1  load MyModule  # MyFunction is defined in this module;
   2  
   3  # Create a modified copy and use the same name:
   4  const MyFunction = @Decorator( MyFunction )
     


Decorators can be overloaded just like normal functions, and be applied to overloaded
functions, as well as class methods. Please see dao.routine.decorator for additional 
information.