load help; @[name] dao.routine @[name] @[title] Routine @[title] @[text] Routine (function) is a relative independent block of code that can be repeatedly executed by invoking it when and where it is needed. It can accept parameters to changes its behaviour. It may also return results to its caller. In Dao, the term routine and function can be used interchangably. @[subsection] Definition @[subsection] Dao routines are declared with keyword @[green]routine@[green] For example, @[code(dao)] routine func( first, second ) { first += 10; second += "test"; return first, second; # return more than one results. } var (ret1, ret2) = func( 111, "AAA" ); var ret3 = func( ret1, ret2 ); @[code(dao)] defines a function that can take two parameters as inputs, and return two values as outputs. @[subsection]Parameter Type and Default Value@[subsection] Routine parameters can have type annotations, and a default value can also be specified for a parameter. @[code] routine MyRout( name: string, index = 0 ) { io.writeln( "NAME = ", name ) io.writeln( "INDEX = ", index ) } @[code] Here @[cyan]name@[cyan] is annotated as type 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] @[text] @[name] dao.routine.closure @[name] @[title] Anonymous Routine and Closure @[title] @[text] Dao supports routines as first class objects. So they can be created at running time and used just like other objects. They may be created as anonymous routines or closures, depending on how they are declared. The syntax to declare an anonymous routine or closure is nearly identical to the definition of a normal function, except the following differences: @[list] -- No need for a function name; -- Its function body may access the local variables of the outer function; @[list] Here is a simple anonymous function, @[code] var rout = routine( name: string, value = 0 ){ io.writeln( name, value ) return name.size() + value } rout( "abc", 123 ) @[code] The only difference of this declaration from normal function declaration is the lacking of function name here. In the above example, the created routine does not access the local variables of the outer routine. So it is created as ordinary anonymous routine instead of closure. Here is another example where a local variable of the outer routine is accessed, @[code] routine MakeClosure( start: int ) { return routine( offset: int ){ return start + offset } } var rout = MakeClosure( 100 ); rout( 123 ) @[code] Due to the access of local variable "start" of "MakeClosure()", the created routine "rout" will be a closure. When a closure is created, it will store the accessed outer scope local variables as up values in the created routine. For primitive type variables, their current value will be copied to the closure's up values; for other types, only their references are copied. Once a closure is created, it can work without the original context where it was created. The main difference between an anonymous function and a closure is whether it accesses the local variable of the outer function. This difference leads to another important difference in what happens when an expression for running time routine creation is executed. If the expression should produce a closure, a @[green]new@[green] routine with captured up values is always created; but if the expression should produce an ordinary anonymous routine, the @[green]same@[green] routine might be returned. For example, the following "MakeRoutine()" function will always return the same routine object, @[code] routine MakeRoutine() { return routine( value: double ){ return value * value } } io.writeln( MakeRoutine(), MakeRoutine() ) @[code] This happens when the anonymous function has no static variables. If it has, a new routine is always created just like new routines are always created for closures. For example, the following "MakeRoutine()" function will always return a new routine object, @[code] routine MakeRoutine() { return routine( value: double ){ static dummy = 123 return value * value } } io.writeln( MakeRoutine(), MakeRoutine() ) @[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 an implicit 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] var 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; var 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!' ); var 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]