close Warning: Can't synchronize with repository "(default)" (/var/svn/tolp does not appear to be a Subversion repository.). Look in the Trac log for more information.

Version 3 (modified by Víctor de Buen Remiro, 16 years ago) (diff)

--

OOP in TOL

La principal diferencia del nuevo TOL 2.0.1 con respecto a sus predecesores será la apuesta por la programación orientada al objeto (OOP).

Se trataría de que el usuario pudiera definir estructuras de NameBlock, es decir clases virtuales puras en la nomenclatura OOP, con una API mínima para poder usarla como descriptor de argumento en funciones de forma similar al Struct en Set sólo que se permite establecer la API de los métodos.

Clases primarias

Son aquellas clases que no heredan de ninguna otra previa sino que se definen por sí mismas. En cierta manera, una clase primaria es a un NameBlock lo que un Struct es para un Set: le obliga a seguir una pauta organizativa, aunque los requisitos que conlleva son algo distintos.

Clases estructurales

Llamaremos clase estructural a aquella que no tiene ningún método.

Class Doc
{ 
  Text _.name;
  Text _.description
};

Clases no estructurales

Si tiene algún método le diremos no estructural.

Class Doc
{ 
  Text _.name;
  Text _.description;
  Text getName(Real unused) { _.name } 
};

Clases virtuales

Una clase no estructural será virtual si tiene algún método no definido, el cual deberá ser definido en alguna clase heredada de esta, o bien en la propia instanciación de objetos.

Class Doc
{ 
  Text _.name;
  Text _.description;
  Text getName(Real unused) { _.name };
  Text getSize(Real unused)
};

Clases virtuales puras

Una clase primaria virtual pura es aquella que en la que ningún método tiene una definición por defecto

Class Vector
{ 
  Matrix  get.column  (Anything unused);
  Real    has.timeInfo(Anything unused);
  TimeSet dating      (Anything unused);
  Date    firstDate   (Anything unused);
  Date    lastDate    (Anything unused)
};

Clases heredadas

Es posible crear clases heredadas de otras que implementen métodos o asignen valores por defecto a miembros. También está permitida la herencia múltiple siempre y cuando no exista conflicto entre los métodos y miembros heredados. Si no desea cambiar ninguno de los miembros o métodos por defecto ni añadir nada nuevo, simplemente se listan las clases de las que se quiere heredar. En otro caso se abrirían llaves y se harían las modificaciones o añadidos pertinentes:

//Si no se quiere cambiar nada con herencia múltiple se enumeran las clases
//antecesoras
Class VectorDoc: Vector, Doc;

//Con herencia simple no tiene mucho sentido no cambiar nada
//pues sería una simple clonación de tipos
Class VectorDoc.Ser: VectorDoc
{
  Serie  _ser;
  Matrix  get.data    (Anything unused) { Tra(SerMat(_ser)) };
  Real    has.timeInfo(Anything unused) { True };
  TimeSet dating      (Anything unused) { Dating(_ser) };
  Date    firstDate   (Anything unused) { First(_ser) };
  Date    lastDate    (Anything unused) { Last(_ser) }
};

Class VectorDoc.Mat: VectorDoc
{
  Matrix _mat;
  Matrix  get.data    (Anything unused) { _mat }
  Real    has.timeInfo(Anything unused) { False };
  TimeSet dating      (Anything unused) { W };
  Date    firstDate   (Anything unused) { UnknownDate };
  Date    lastDate    (Anything unused) { UnknownDate }
};

Instancias

Una instancia de una clase es un NameBlock que cumple la API definida por dicha clase y define al menos todos los miembros sin valor por defecto y todos los métodos no implementados. Obsérvese que el orden de declaración de los miembros es irrelevante e independiente del orden de herencia de las clases.

VectorDoc.Ser vd.ser =
[[
  Text    _.name = "Viernes";
  Text    _.description = "Es 1 los días viernes y 0 el resto";
  Serie   _ser = CalInd(WD(5),C)
]];

VectorDoc.Mat vd.mat =
[[
  Text   _.name = "Constante";
  Matrix _mat = SetCol(NCopy(1,100));
  Text   _.description = "Siempre vale 1"
]];

Las clases vistas como tipos de usuario

Los nombres de clase funcionarán como tipos definidos por el usuario a todos los efectos, salvo alguna excepción debida a las limitaciones del parser de TOL y que quedarán debidamente documentadas. Es posible entonces declarar argumentos de función de una clase determinada lo cual admitirá cualquier NameBlock que sea instancia de esa clase o cualquier clase heredada de ella.

Matrix sum(Vector a, Vector b)
{
  a::get.data(0) + b::get.data(0)
};

Matrix c = sum(vd.ser, vd.mat);

Otros ejemplos de clases

Esta otra sería una clase primaria parcialmente virtual pues tiene algunos miembros y métodos definidos por defecto y otros no

Class Input
{
  VectorDoc _.data;
  Real  _.enabled = True;
  Polyn _.omega = 1;
  Polyn _.delta = 1;
  Ratio transferFunction (Anything unused)
  {
    _.omega / _.delta
  };
  Matrix eval(Polyn omega, Polyn delta)
  {
    Polyn  _.omega := omega;
    Polyn  _.delta := delta;
    MatDifEq(transferFunction, _.vector::get.column(0))
  }
};

Class Output
{
  VectorDoc _.data;
  Set _.arima
};

El miembro privado reservado _this

Todos los NameBlock, sean o no instancia de una clase, tienen un miembro privado llamado _this al que se puede acceder desde todos sus métodos.

//Example of using implicit private member _this
NameBlock a = 
[[
  Text _.name = "a";
  Text getName(Real unused) { _this::_.name }
]];

//User cannot overwrite _this due to it's a reserved word
NameBlock b = 
[[
  Text _.name = "b";
  NameBlock _this = a;
  Text getName(Real unused) { _this::_.name }
]];