[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);