    [NAME]
    ALL.misc.comparison.decorator

    [TITLE]
    Function Decorator (Python)

    [DESCRIPTION]

    Decorators are a special type of functions that can be used to enhance the
    functionalities of other functions by decorating them.

     0.1   Decorators for Single Functions

    In Python, a decorator is just a callable that can take a function as an input argument
    and return a replacement function as output. For example,

       1  def Decorator( func ):
       2      def newfunc():
       3          ret = func()
       4          return ret + 123
       5      return newfunc
       6
       7  def Foo():
       8      return 456
       9
      10  deco = Decorator( Foo )
      11  deco()

    Dao decorators are quite different from Python decorators. Dao decorators do not return
    replacement functions, instead, they are defined as the templates from which the
    replacement functions can be created. Such replacement functions may or may not call the
    original function, this is the same as Python decorators, but Dao decorators are typed
    and can be strictly typed. So all the static type checking that can be applied to normal
    functions can also be applied to decorators as well.

    An equivalent Dao decorator for the above Python example is,

       1  routine @Decorator( func(args) : routine< =>int > )
       2  {
       3      ret = func( args, ... )  # call the original function;
       4      return ret + 123
       5  }
       6  routine Foo()
       7  {
       8      return 456
       9  }
      10  deco = @Decorator( Foo )
      11  deco()

    Where the parameter type routine< =>int > of @Decorator() indicates that this decorator
    can only be applied to functions that can take no parameter and return an integer. args
    is a specially defined variable of tuple type to hold the parameters that will be passed
    to the decorated function. The ... in the end of the argument list indicates that the
    call must expand the previous tuple argument in the argument list, namely, removing the
    tuple and placing its items in the argument list.

    In both Python and Dao, decorators can be applied at function definition sites in the
    same way.

     0.2   Decorators for Any Functions

    If one wants to define a decorator that can be applied to any functions. In Python, one
    might do,

       1  def Decorator( func ):
       2      def newfunc( *args, **kwargs ):
       3          print "Calling with: %s, %s" % (args, kwargs)
       4          return func( *args, **kwargs )
       5      return newfunc
       6
       7  def Foo( a ):
       8      return a + 456
       9
      10  deco = Decorator( Foo )
      11  deco( 123 )

    The equivalent in Dao would be,

       1  routine @Decorator( func(args) : routine )
       2  {
       3      io.writeln( 'Calling with:', args, ... )
       4      return func( args, ... )  # call the original function;
       5  }
       6  routine Foo( a )
       7  {
       8      return a + 456
       9  }
      10  deco = @Decorator( Foo )
      11  deco( 123 )

     0.3   Overloaded Decorators

    If one wants to write a decorator for multiple type of functions, in Python one would
    have to create decorators as in the above Python examples and check the argument types to
    handle different types of functions. Because Python does not support function
    overloading.

    In Dao, one could simply create different decorators for different target functions, and
    overload them with the same name. For example,

       1  routine @Decorator( func(args) : routine<int=>int> )
       2  {
       3      return func( args, ... ) + 123
       4  }
       5  routine @Decorator( func(args) : routine<string=>string> )
       6  {
       7      return func( args, ... ) + 'abc'
       8  }
       9
      10  @Decorator  # the first decorator will be applied;
      11  routine Foo( a : int )
      12  {
      13      return a * 100
      14  }
      15
      16  @Decorator  # the second decorator will be applied;
      17  routine Foo( a : string )
      18  {
      19      return a + '##';
      20  }
      21
      22  f = @Decorator( Foo )
      23  f( 123 )
      24  f( 'xyz' )

    When the target function is also overloaded, the decorator will be applied to each of the
    overloaded functions, and create a new (and possible also overloaded as well) function.