[NAME]
ALL.dao.tutorial.class

[TITLE]
Class, Mixin, OOP and AOP

[DESCRIPTION]

Object-Oriented Programming (OOP) is supported in Dao by offering class-based features 
such as data abstraction, encapsulation, polymorphism and inheritance etc. And such
support for OOP is further enhanced by interface.

 0.1  Class Definition 

A class is a user-defined data structure consisting data fields and member methods, 
which define the states and behaviours for the instances of the class. Class supports
three types of fields:
  *  constant: declared with keyword const;
  *  static variable: declared with keyword static;
  *  instance variable: declared with keyword var; 
Such fields can be declared with or without explicit types, and with or without default 
or initialization values, in the same way as specifying types and/or default values for
function parameters. For example, the following can be used for instance variables,
     
   1  var variable;
   2  var variable = init_value;
   3  var variable : typename;
   4  var variable : typename = init_value;
     

Class methods must be declared with keyword routine (or its alias keywords function or 
sub) for constructors and normal methods, or keyword operator for operator overloading.

The access of class fields and methods can be restricted by three permission keywords:
  *  public: publically accessible without restriction;
  *  protected: accessible from the class and its derived classes;
  *  private: only accessible from the class; 

Here is a simple class,
     
   1  class ClassOne
   2  {
   3      var index = 0;
   4      var name  : string
   5      var words : list<string> = {}
   6  
   7      routine ClassOne( name :string, index = 0 ){
   8          self.name = name;
   9          self.index = index;
  10      }
  11  }
     

Within class methods, the special variable self represents the current class instance. 
Class methods may be declared inside class body and defined outside in the same way as in
C++, but in Dao, one should make sure that, the parameter list must be exactly the same 
in the places for declaration and definition.

 0.2  Class Instance 

Class constructors are the methods that have name the same as the class name. A class
instance can be created by invoking a constructor of the class in the same way as a
function call,
     
   1  object = ClassOne( 'abc' )
     
Like in Python, the constructors are not used to create class instances, instead, an
instance is created before, and then the constructor is called after to initialize the
instance.

For a class without parent classes and without constructors, its instances may also be
created by enumerating the members of the class,
     
   1  class Point3D
   2  {
   3      var x = 0D;
   4      var y = 0D;
   5      var z = 0D;
   6  }
   7  point = Point3D::{ 1, 2, 3 };
     
The names of instance variables may also be specified in enumeration,
     
   1  point = Point3D::{
   2      y => 2,
   3      x => 1,
   4      z => 3,
   5  };
     

When you create a class instance using enumeration, the instance is created, and filled
with the values in the enumeration. Instance creation by enumeration is much faster than
creation by invoking class constructor, since no class constructor is called and there is
no overhead associated with function call (parameter passing, running time context
preparation for the call etc.). So such instance creation is very desirable for creating
many instances for simple classes, in which there are no complicated initialization
operations.

 0.3  Member Variable 

As mentioned above, instance variables are declared in class constructor using var 
keyword. Class constant can be declared using const keyword, and static member can be 
declared using static keyword as in C++: 
     
   1  class Klass
   2  {
   3      const aClassConst = "KlassConst";
   4      static aClassStatic;
   5  }
     
Here aClassConst will be constant belonging to a Klass. While aClassStatic will be a 
static variable in the class scope.

 0.4  Setters, Getters and Overloadable Operators 

Instead of defining setXyz() methods, one can define .Xyz=() method as setter operator, 
so that modifying class member Xyz by obj.Xyz=abc will be allowed; similarly, if .Xyz() 
is defined, get the value by obj.Xyz will also be allowed: 
     
   1  class MyNumber
   2  {
   3      private
   4     
   5      var value = 0;
   6  
   7      public
   8  
   9      routine MyNumber( v = 0 ){
  10          value = v;
  11      }
  12  
  13      operator .value=( v ){ value = v; io.writeln( "value is set" ) }
  14      operator .value(){ return value }
  15  }
  16  
  17  num = MyNumber( 123 )
  18  num.value = 456
  19  io.writeln( num.value )
     


As you may guess, accessing instance variable through getters and setters are more
expensive than using them as public variables! They should be used only when they make
things more convenient (for example, when you want them to do extra work when a variable
is accessed).

Other supported operators for overloaing include:
  1. [operator ()(...)] for function call;
  2. [operator [](...)] for getting item(s);
  3. [operator []=(...)] for setting item(s);
Basic arithmetic operators are also supported for overloading.

 0.5  Method Overloading 

Class methods can be overloaded in the same way as normal functions. Class constructor
may also be overloaded by simply adding a method with the same name as the class. For
example, class MyNumber can be modified to hold numeric value only: 
     
   1  class MyNumber
   2  {
   3      private
   4  
   5      var value : int = 0;
   6  
   7      public
   8  
   9      routine MyNumber( value = 0 ){ # accept integer as parameter
  10          self.value = value;
  11      }
  12  
  13      # overloaded constructor to accept MyNumber as parameter:
  14      routine MyNumber( value : MyNumber ){ self.value = value.value }
  15  
  16      operator .value=( v : int ){ value = v }
  17      operator .value=( v : MyNumber ){ value = v.value }
  18      operator .value(){ return value }
  19  }
  20  
  21  num1 = MyNumber( 123 )
  22  num1.value = 456
  23  io.writeln( num1.value )
  24  
  25  num2 = MyNumber( num1 )
  26  io.writeln( num2.value )
  27  
  28  num2.value = 789
  29  io.writeln( num2.value )
  30  
  31  num2.value = num1
  32  io.writeln( num2.value )
     


 0.6  Inheritance 
     
   1  class ColorRBG
   2  {
   3      var Red = 0.0;
   4      var Green = 0.0;
   5      var Blue = 0.0;
   6  
   7      routine ColorRBG( r = 0.0, g = 0.0, b = 0.0 ){
   8          Red = r;
   9          Green = g;
  10          Blue = b;
  11      }
  12      routine ColorRGB( name : enum<white,black,red,green,blue,yellow,magenta,cyan> ){
  13          switch( name ){
  14          case $white:   Red = Green = Blue = 1.0
  15          case $black:
  16          case $red:     Red = 1.0
  17          case $green:   Green = 1.0 
  18          case $blue:    Blue = 1.0
  19          case $yellow:  Red = Green = 1.0
  20          case $magenta: Red = Blue = 1.0
  21          case $cyan:    Green = Blue = 1.0
  22          }
  23      }
  24  
  25      routine setRed( r ){ Red = r; }
  26      routine setGreen( g ){ Green = g; }
  27      routine setBlue( b ){ Blue = b; }
  28  
  29      routine getRed(){ return Red; }
  30      routine getGreen(){ return Green; }
  31      routine getBlue(){ return Blue; }
  32  }
  33  
  34  yellow = ColorRBG( 1, 1, 0 ); # create an instance.
     
The following will define a derived class of ColorRBG, 
     
   1  class ColorRGBA : ColorRBG
   2  {
   3      var alpha = 0.0; # alpha component for tranparency.
   4  
   5      routine ColorRGBA( r = 0.0, g = 0.0, b = 0.0, a = 0.0 ) : ColorRBG( r, g, b ){
   6          alpha = a;
   7      }
   8      # Inherit the constructor from ColorRGB that accepts color names:
   9      use routine ColorRGB( name : enum<white,black,red,green,blue,yellow,magenta,cyan> );
  10  }
  11  
  12  yellow2 = ColorRGBA( 1, 1, 0, 0 ); # not tranparent.
  13  yellow2.alpha = 0.5; # change to half tranparency.
  14  
  15  magenta = ColorRGBA( $magenta )
     

In the definition of derived class, the parent class ColorRBG should be put after the 
derived class and be separated with :. (Since 2013-10-20, classic multiple 
inheritance is no longer support. Now mixins are the preferred way to do similar
things.) The constructor parameters for derived class can be passed to parent
classes in the way as shown in the example.

Constructors from the parent class can be inherited by using the use statement, in which
the full function signature of the constructor should be specified.

 0.7   Mixin  

Features introduced in the this and the remaining sections are available only in the
latest devel release and the online version.

Classes to be used as mixins can be specified in a pair of brackets following the class
name. Only classes without parent classes can be used as mixins.
     
   1  class Base
   2  {
   3      var value = 456
   4      routine Meth2(){ io.writeln( self, value ) }
   5  }
   6  
   7  class Mixin ( Base )
   8  {
   9      var index = 123
  10  
  11      routine Meth(){ io.writeln( self, index, value ) }
  12      routine Meth2( a : string ){ io.writeln( self, index, value, a ) }
  13  }
  14  
  15  #
  16  # The "Base" class will be presented only once in "Klass":
  17  #
  18  class Klass ( Base, Mixin )
  19  {
  20      var index = 123456
  21      routine Meth2( a : int ){ io.writeln( self, index, value, a ) }
  22  }
  23  
  24  k = Klass()
  25  
  26  io.writeln( k.index )
  27  
  28  k.Meth()
  29  k.Meth2()
  30  k.Meth2( 'abc' )
  31  k.Meth2( 789 )
     


 0.8   Class Decorator  

(New in the latest devel release and online version)
Class decorators are classes that can be used modify other classes. The modification is
done by using such class as a mixin base class to inject (combine) its members into the
modified class, and by automatically applying its method decorators to the methods of the
modified class.
For such auto decorator application, only decorators with explicitly specified decoration
targets are automatically applied. Such targets are expressed as prefix and suffix rules 
which can be expressed in the following ways:
  1. Prefix~ : a prefix pattern. The decorator will be auto applied to methods that have 
     names with such prefix;
  2. ~Suffix : a suffix pattern. The decorator will be auto applied to methods that have 
     names with such suffix;
  3. Prefix~Suffix : a prefix and suffix pattern. The decorator will be auto applied to 
     methods that have names with such prefix and suffix;
  4. ~ : an empty prefix and suffix pattern. The decorator will be auto applied to any
     methods.


When multiple mixins are used in a host class, the decorators of the first mixin are
applied the last. And the first decorator of the same decorator is also applied the last
as well.
     
   1  class @Header
   2  {
   3      static routine @Delimiter( meth(args) : routine ) for ~ {
   4          io.writeln( '=======================' )
   5          return meth( args, ... )
   6      }
   7      routine @Delimiter( meth(args) : routine ) for ~ {
   8          io.writeln( '-----------------------' )
   9          return meth( args, ... )
  10      }
  11  }
  12  class @Decorator
  13  {
  14      var value = 654321
  15  
  16      routine @Test( meth(args) :routine<self:@Decorator> ) for Test {
  17          io.writeln( 'Decorator::Test()', value )
  18          meth( args, ... );
  19      }
  20      routine @Prefix( meth(args) :routine<self:@Decorator> ) for Prefix~ {
  21          io.writeln( 'Decorator::Prefix()' )
  22          meth( args, ... );
  23      }
  24      routine @Suffix( meth(args) :routine<self:@Decorator> ) for ~Suffix {
  25          io.writeln( 'Decorator::Suffix()' )
  26          meth( args, ... );
  27      }
  28      routine @Prefix_Suffix( meth(args) :routine<self:@Decorator> ) for Prefix~Suffix {
  29          io.writeln( 'Decorator::Prefix_Suffix()' )
  30          meth( args, ... );
  31      } 
  32  }
  33  
  34  class MyMixin ( @Header, @Decorator )
  35  {
  36      routine Test(){
  37          io.writeln( 'MyMixin::Test()' )
  38      }
  39      routine PrefixTest(){
  40          io.writeln( 'MyMixin::PrefixTest()' )
  41      }
  42      routine TestSuffix(){
  43          io.writeln( 'MyMixin::TestSuffix()' )
  44      }
  45      routine PrefixTestSuffix(){
  46          io.writeln( 'MyMixin::PrefixTestSuffix()' )
  47      }
  48  }
  49  
  50  obj = MyMixin()
  51  obj.Test()
  52  obj.PrefixTest()
  53  obj.TestSuffix()
  54  obj.PrefixTestSuffix()
     


 0.9   Aspect Class  

(New in the latest devel release and online version)

In Dao, a class decorator can be effectly used as an aspect for AOP, if decoration target
patterns are specified for auto application. The target patterns are can be specified in 
the same way as the target patterns for class method decorators.

The fields of such class will be automatically injected to normal classes selected
according to the affix rules, and the decorators defined in such aspect class are
automatically applied to the methods (selected according to the same affix rules) of the
normal classes.
     
   1  class @AspectForAnyClass for ~  # To be applied to any classes;
   2  {
   3      var injected : list<int> = {}
   4  
   5      # This is not a decorator!
   6      routine @AspectForAnyClass(){
   7          io.writeln( 'In @AspectForAnyClass():' );
   8          injected = { 1, 2, 3 }
   9      }
  10  
  11      # This decorator will also be applied to the default constructors:
  12      routine @DecoratorForAnyMethod( meth(args) : routine ) for ~ {
  13          io.writeln( 'In @DecoratorForAnyMethod():', std.about(meth) )
  14          io.writeln( injected )
  15          return meth( args, ... )
  16      }
  17  }
  18  
  19  # For classes with names prefixed with My:
  20  class @AspectForMyClasses for My~
  21  {
  22      routine @Method( meth(args) : routine ) for Method~ {
  23          io.writeln( 'In @AspectForMyClasses::@Method():', std.about(meth) )
  24          return meth( args, ... )
  25      }
  26  }
  27  
  28  class MyClass
  29  {
  30      routine Method(){ io.writeln( 'MyClass::Method()' ) }
  31  }
  32  
  33  k = MyClass()  # Invoke the default constructor of Klass;
  34  k.Method()