load help;


@[name]
dao.routine
@[name]

@[title]
Routine
@[title]


@[text]

Routine is a block of codes, once defined, can be used in different places
at different time repeatedly. It can accept parameters to changes its
behaviour. It may also return results to its callee.


Dao routines are declared with keyword @[green]routine@[green]
or @[green]function@[green] or @[green]sub@[green] 
(which are exactly equivalent to @[green]routine@[green]),

@[code(dao)]
routine func( a, b )
{
   io.writeln( a, b );
   a = 10;
   b = "test";
   return a, b; # return more than one results.
}

r1, r2;
( r1, r2 ) = func( 111, "AAA" );
r3 = func( r1, r2 );
io.writeln( "r1 = ", r1 );
io.writeln( "r2 = ", r2 );
io.writeln( "r3 = ", r3 );
@[code(dao)]



@[subsection]Named Parameter@[subsection]

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



@[subsection]Parameter Type and Default Value@[subsection]

It is also possible to specify the type or the default value of a parameter.
@[code]
routine MyRout( name : string, index = 0 )
{
   io.writeln( "NAME  = ", name )
   io.writeln( "INDEX = ", index )
}
@[code]
Here @[cyan]name@[cyan] is specified as string, and @[cyan]index@[cyan]
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.



@[subsection]Routine Overloading@[subsection]

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.
@[code]
routine MyRout( index : int, name = "ABC" )
{
   io.writeln( "INDEX = ", index )
   io.writeln( "NAME  = ", name )
}

MyRout( "DAO", 123 ) # invoke the first MyRout()
MyRout( 456, "script" ) # invoke the second MyRout()
@[code]



For coroutines, please see @[node]module.core.coroutine@[node].


@[text]





@[name]
dao.routine.anonymous
@[name]

@[title]
Anonymous Routine
@[title]


@[text]

@[subsection]Routine As First Class Object@[subsection]

Dao also support first class functions / routines. They can be created in the following way:
@[code]
foo = routine( x, y : TYPE, z = DEFAULT )
{
   codes;
}
@[code]
The definition of such functions is identical to the normal function definition, except
the following differences:
@[list]
==there is no need for a function name, but the created function must be assigned to a variable;
==the default value expressions for parameters do not necessary to be constant expressions,
they are evaluated at running time when the function is created;
==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.
@[list]


Here is an example,
@[code]
a = "ABC";

rout = routine( x, y : string, z = a+a ){
    a += "_abc";
    io.writeln( "lambda ", a )
    io.writeln( "lambda ", y )
    io.writeln( "lambda ", z )
}

rout( 1, "XXX" );
@[code]

@[text]








@[name]
dao.routine.section
@[name]

@[title]
Code Section Methods
@[title]


@[text]



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.
@[code]
routine meth_name( meth_params ) [sect_params => sect_return] => meth_return
{
	...
}
@[code]
The parameter list prototype @[cyan]sect_params@[cyan] for the code section specifies
what kind of parameters this method will pass to the code section; and the section
return type @[cyan]sect_return@[cyan] indicates what type of value this method expects
the code section to return.


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


For example, list type has a code section method for sorting with 
the following prototype,
@[code]
sort( self :list<@T>, k=0 ) [X :@T, Y :@T => int] => list<@T>
@[code]
Here the code section parameters @[cyan]X@[cyan] and @[cyan]Y@[cyan]
are used to pass two items of the list for comparison.
The code section return type @[green]int@[green] indicates that
the code section is expected to return an integer as the comparison result.
So this @[green]sort()@[green] can be use in the following ways,
@[code]
numlist = { 11, 44, 21, 32, 56, 67, 25 }

# Sort all by ascend order:
numlist.sort::{ X < Y }

# Sort by descend order until the largest 3 items are sorted:
numlist.sort( 3 )::{ X > Y }
# Now the first 3 items of the list is the largest 3 items;

tuplist = { ( 2, 'ghi' ), ( 1, 'def' ), ( 2, 'abc' ), ( 1, 'abc' ) }
tuplist.sort::{
	# First sort by the first items of the tuples;
	if( X[0] != Y[0] ) return X[0] < Y[0];
	# Then sort by the second items;
	return X[1] < Y[1];
}
@[code]


In a user defined code section method, the @[green]yield@[green] 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,
@[code]
# A function that can be called with a code section.
# The code section is expected to take an integer as parameter,
# and return a string.
routine Test() [X :int => string] => string
{
	io.writeln( 'In functional method!' );
	s = yield( 123 ); # execute the code section;
	io.writeln( 'Yielded value:', s );
	return s;
}

Test::{
	io.writeln( 'In code section:', X );
	return 'abc';
}
@[code]


@[text]



@[name]
dao.routine.decorator
@[name]

@[title]
Function Decorator
@[title]

@[text]

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


Decorators are a special type of functions that can be used to
enhance the functionalities of other functions by decorating them,
which may either modify these functions or create a modified version
of these functions.


There are different ways to decorate a function, but only functions
that are decorated at their defintion points are modified.
In all other cases, function decoration always produces new and 
modified copies of the original functions.


A decorator is almost identical to a noraml function except that it
must be declared with a name prefixed with @, and 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.


@[subsection]
Decorator for Any Functions
@[subsection]

If a decorator will be used to decorate any functions,
the routine type for the first parameter of the decorator
can be declared as the most generic function type @[green]routine@[green]


Here is a simple decorator that can decorate any function.
@[code]
routine @Decorator( func(args) : routine )
{
	io.writeln( 'Calling function:', std.about(func) );
	return func( args, ... ); # ... for parameter expanding;
}
@[code]


Decorators can be applied at the places where functions are defined.
@[code]
@Decorator()
routine Function(){ io.writeln( 'Function()' ); }
@[code]


If the decorator does not take any parameter other than
the function to be decorated, the brackets can be omitted:
@[code]
@Decorator
routine Function( a : int ){ io.writeln( 'Function(int)', a ); }

Function();
Function(123);
@[code]



@[subsection]
Decorator for Specific Function Type
@[subsection]

A decorator can be defined such that it can only be applied to 
a specific type of functions, if the type of such functions is
specified as the first parameter of the decorator.


Here is a deocrator that can only be applied to functions that
accepts an integer as parameter and returns a string.
For a decorator for testing such as this one, the expected
output can be passed as additional parameters to the decorator:
@[code]
routine @TestDecorator( func(args) : routine<index:int=>string>, expected = '' )
{
	res = func( args, ... );
	io.writeln( res );
	io.writeln( 'Test result:', res == expected ? 'passed' : 'failed' );
	return res;
}

@TestDecorator( 'Hello' )
routine Hello( index = 0 )
{
	io.writeln( 'Calling Hello(int)' );
	return 'Hello';
}

Hello();
@[code]



@[subsection]
Overloaded Decorator
@[subsection]

Decorators can be overloaded just like the normal functions.


Here is an overloaded deocrator that can only be applied to functions
that accepts a string as parameter and returns an integer.
@[code]
routine @TestDecorator( func(args) : routine<name:string=>int>, expected = 0 )
{
	res = func( args, ... );
	io.writeln( res );
	io.writeln( 'Test result:', res == expected ? 'passed' : 'failed' );
	return res;
}
@[code]



# Decorators can be chained:
@[code]
@Decorator
@TestDecorator( 123 )
routine Hello( name : string )
{
	io.writeln( 'Calling Hello(string)', name );
	return 123;
}

io.writeln( Hello( 'abc' ) );
@[code]



@[subsection]
Decorator in Expression
@[subsection]

Decorator can be used in the same way as normal functions,
namely calling a decorator like a normal function,
and pass the function to be decorated and other values
as parameters to the decorator.
@[code]
anotherHello = @Decorator( Hello )
@[code]
Using decorator in this way will produce a modified copy of the function.


If all the parameters passed to a decorator called in constant form
(namely not used through a varaible), this expression of calling the decorator
is a constant expression and can be evaluated at compiling time.
@[code]
const Hello3 = @Decorator( Hello )
Hello3( 'def' )
@[code]

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.
@[code]
load MyModule  # MyFunction is defined in this module;

# Create a modified copy and use the same name:
const MyFunction = @MyDecorator( MyFunction )
@[code]



When a decorator is called in non-constant expression,
the decoration will be done at running time,
@[code]
routine Hello2( index = 123 )
{
	io.writeln( 'Calling Hello2(int)', index );
	return 'Hello';
}
# Running time decoration:
func = @TestDecorator( Hello2, 'Hello' );
io.writeln( '--------' )
func(123)

func = @TestDecorator( func );
io.writeln( '--------' )
func(123)
@[code]


Just like normal functions, decorators can be assigned to variables
and used at running time:
@[code]
deco = @Decorator;
func = deco( func );

io.writeln( '--------' )
func(789);
@[code]



@[subsection]
Decorator for Class Method
@[subsection]

Decorators can be applied to class methods.
Such decorators can be defined outside of the class
as well as inside the class as a class member.


If the routine type of the first parameter of a decorator does not
contain a self parameter, this decorator can be applied to static methods,
@[code]
routine @StaticDecorator( meth(args) :routine<id:int=>int>, value = 123 )
{
	io.writeln( args, value );
	args.id = value;
	return meth( args, ... );
}
@[code]
Otherwise, it can be applied to instance methods,
@[code]
routine @MethodDecorator( meth(args) :routine<self:@T,id:int=>int>, value = 123 )
{
	io.writeln( args, value );
	args.id = value;
	return meth( args, ... );
}
@[code]


When a decorator is defined as a class method,
it must be declared as a static method, 
because its first parameter must be a routine type,
@[code]
class Klass
{
	static routine @ClassDecorator( meth(args) :routine<id:string=>?>, value = 'abc' ){
		io.writeln( args, value );
		args.id = value;
		return meth( args, ... );
	}

	# Decorator can be applied to class methods:
	@StaticDecorator( 456 )
	static routine StaticMeth( id :int ){ io.writeln( id ); return id }

	@ClassDecorator
	static routine StaticMeth( id :string ){ io.writeln( id ) }

	@MethodDecorator( 789 )
	routine Meth( id :int ){ io.writeln( id ); return id }
}

Klass::StaticMeth( 0 );
Klass::StaticMeth( 'a' );

k = Klass();
k.Meth(1);
@[code]



@[text]
