[NAME]
ALL.dao.routine.decorator

[TITLE]
Function Decorator (Removed)

[DESCRIPTION]

WARNING: This feature has been removed!

Decorators are a special type of functions that can be used to enhance the functionalitie
s of other functions by decorating them, which may either modify these functions or creat
e 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 produ
ces 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 paramet
ers that will be passed to the function, must also be declared inside a pair of brackets 
right after the name of the first parameter.

 0.1   Decorator for Any Functions  

If a decorator will be used to decorate any functions, the routine type for the first par
ameter of the decorator can be declared as the most generic function type routine.

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


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


If the decorator does not take any parameter other than the function to be decorated, the
brackets can be omitted: 
     
   1  @Decorator
   2  routine Function( a : int ){ io.writeln( 'Function(int)', a ); }
   3  
   4  Function();
   5  Function(123);
     


 0.2   Decorator for Specific Function Type  

A decorator can be defined such that it can only be applied to  a specific type of functi
ons, 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 para
meter and returns a string. For a decorator for testing such as this one, the expected ou
tput can be passed as additional parameters to the decorator: 
     
   1  routine @TestDecorator( func(args) : routine<index:int=>string>, expected = '' )
   2  {
   3      res = func( args, ... );
   4      io.writeln( res );
   5      io.writeln( 'Test result:', res == expected ? 'passed' : 'failed' );
   6      return res;
   7  }
   8  
   9  @TestDecorator( 'Hello' )
  10  routine Hello( index = 0 )
  11  {
  12      io.writeln( 'Calling Hello(int)' );
  13      return 'Hello';
  14  }
  15  
  16  Hello();
     


 0.3   Overloaded Decorator  

Decorators can be overloaded just like the normal functions.

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


# Decorators can be chained: 
     
   1  @Decorator
   2  @TestDecorator( 123 )
   3  routine Hello( name : string )
   4  {
   5      io.writeln( 'Calling Hello(string)', name );
   6      return 123;
   7  }
   8  
   9  io.writeln( Hello( 'abc' ) );
     


 0.4   Decorator in Expression  

Decorator can be used in the same way as normal functions, namely calling a decorator lik
e a normal function, and pass the function to be decorated and other values as parameters
to the decorator. 
     
   1  anotherHello = @Decorator( Hello )
     
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 thro
ugh a varaible), this expression of calling the decorator is a constant expression and ca
n be evaluated at compiling time. 
     
   1  const Hello3 = @Decorator( Hello )
   2  Hello3( 'def' )
     

This feature can be exploited to create modified copies of existing functions that are im
ported 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 = @MyDecorator( MyFunction )
     


When a decorator is called in non-constant expression, the decoration will be done at run
ning time, 
     
   1  routine Hello2( index = 123 )
   2  {
   3      io.writeln( 'Calling Hello2(int)', index );
   4      return 'Hello';
   5  }
   6  # Running time decoration:
   7  func = @TestDecorator( Hello2, 'Hello' );
   8  io.writeln( '--------' )
   9  func(123)
  10  
  11  func = @TestDecorator( func );
  12  io.writeln( '--------' )
  13  func(123)
     


Just like normal functions, decorators can be assigned to variables and used at running t
ime: 
     
   1  deco = @Decorator;
   2  func = deco( func );
   3  
   4  io.writeln( '--------' )
   5  func(789);
     


 0.5   Decorator for Class Method  

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 paramet
er, this decorator can be applied to static methods, 
     
   1  routine @StaticDecorator( meth(args) :routine<id:int=>int>, value = 123 )
   2  {
   3      io.writeln( args, value );
   4      args.id = value;
   5      return meth( args, ... );
   6  }
     
Otherwise, it can be applied to instance methods, 
     
   1  routine @MethodDecorator( meth(args) :routine<self:@T,id:int=>int>, value = 123 )
   2  {
   3      io.writeln( args, value );
   4      args.id = value;
   5      return meth( args, ... );
   6  }
     


When a decorator is defined as a class method, it must be declared as a static method,  b
ecause its first parameter must be a routine type, 
     
   1  class Klass
   2  {
   3      static routine @ClassDecorator( meth(args) :routine<id:string=>?>, value = 'abc' ){
   4          io.writeln( args, value );
   5          args.id = value;
   6          return meth( args, ... );
   7      }
   8  
   9      # Decorator can be applied to class methods:
  10      @StaticDecorator( 456 )
  11      static routine StaticMeth( id :int ){ io.writeln( id ); return id }
  12  
  13      @ClassDecorator
  14      static routine StaticMeth( id :string ){ io.writeln( id ) }
  15  
  16      @MethodDecorator( 789 )
  17      routine Meth( id :int ){ io.writeln( id ); return id }
  18  }
  19  
  20  Klass::StaticMeth( 0 );
  21  Klass::StaticMeth( 'a' );
  22  
  23  k = Klass();
  24  k.Meth(1);