    [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.