# FreshLib object oriented programming library.
## Introduction
The latest versions of FreshLib, silently migrated to a new object oriented
programming macro implementation. Now it implements real OOP architecture with
inheritance, polymorphism, virtual methods and properties.
The implementation uses jump tables, so it is pretty fast, especially compared
to the previous implementation.
The syntax is based on pseudo-instructions and is compatible with assembly
language programming style.
The main target for this library is the programming of GUI interfaces, because
the structure of GUI, usually fit very well in the OOP paradigm. But of
course, the library can be used for general purpose OOP programming.
## Object definition. Encapsulation
[#object] `object` macro
[#endobj] `endobj` macro
The definition of the object is provided by `object` / `endobj` macros. The
syntax is very similar to `struct` macros, but the definition can be inherited
and the body may contain more elements:
;begin fasm
object NAME[, PARENT]
BODY
endobj
;end
`PARENT` can be either other object type name or not be specified at all. If `PARENT` is
missing the object has no parent and does not inherits any fields. If `PARENT` is specified,
the object inherits all fields from the parent object.
All field names in the object definition must be local names related to the object name, i.e.
must start with dot character.
The body may contain following elements:
* General FASM data definition fields:
;begin fasm
object TAnimal
.length dd ?
.height dd ?
.weight dd ?
endobj
;end
The fields are aimed to provide storage of private for the object data. Of
course, it is assembly language and the fields are not hidden from the user,
but a good practice is to not use them as an interface. (There are other
members that are to be used as an interface - the parameters and methods).
* object parameter definition through `param` directive. Will be described in
details later.
* object method definition through `method` directive. Will be described in
details later.
### Object parameters; `param` directive;
[#param] `param` macro
The parameters (aka "properties") are object data fields, that are not
necessary memory cells. Instead their values can be read and write by several
flexible ways. These ways are transparent for the programmer. The FreshLib
implementation allows 3 ways to reading writing parameter values:
* By direct read/write to a memory fields.
* By calling object method that to read or write parameter value using any
software method, for example computing the value, or reading it from a file or
even from the network.
* Not reading/writing at all - the parameters can be read-only and/or
write-only.
The syntax of the definition is:
;begin fasm
param PARAM_NAME, GET_TARGET, SET_TARGET
;end
`PARAM_NAME` is the name of the parameter. It must be local related to the
object name (to start with dot).
`GET_TARGET` defines how the value of the parameter will be get. This
parameters can be either `NONE`, object field name or object method name. In
the first case, the parameter can't be read. In the second, the read of the
parameter becomes simple structure field read and in the third, the read of
the parameter will cause the object method to be call and the return value of
the method will be accepted as a value of the parameter.
The get method must have no arguments and must be defined in the object
definition as normal method.
`SET_TARGET` defines how the value will be write to the parameter. Again we
can use `NONE`, field name or method name. The only difference with the
`GET_TARGET` is that the set method has one argument - the new value of the
parameter.
### Object methods; `method` directive; `abstract` directive;
[#method] `method` macro
[#abstract] `abstract` macro
This directive defines a method field in the object. The syntax is very
similar to the `proc` macro directive:
;begin fasm
method NAME, [ARGUMENTS]
or
abstract NAME, [ARGUMENTS]
;end
`NAME` must be local related to the object name. The arguments can be
arbitrary count and also must start with dot (local).
Besides the explicitly defined arguments, one hidden argument `.self` is
defined for every method, that contains a pointer to the object instance in
the moment when the method is called. The `.self` argument is the first of all
arguments in the method.
The only difference between `method` and `abstract` variants is that the
methods defined with `abstract` keyword does not need to be implemented in the
given class. The abstract methods are simply placeholders for the children
object methods. They allow polymorphic calls of the method in the children
objects.
Every non-abstract method, defined in the object need to be implemented later
in the code. The implementation looks just like `proc` procedure definition,
with the difference that `method` keyword is used. In the implementation,
there is no arguments, because they are already defined in the object type
definition.
The methods can be override in the children classes. The inherited method is
still accessible through `inherided` command. This way the methods chains can
be called when needed.
;begin fasm
method OBJ_NAME.METHOD_NAME
begin
CODE
endp
;end
As is seen from the above description, the object type itself contains in the
same container (capsule) all needed data and the code, needed to process this
data. This property of the objects is called *Encapsulation*.
Some think that "encapsulation" is something about hiding data or code inside
the objects, but this is not the case in the common case.
And of course in assembly language hiding data or code is impossible at all.
The user have always access to all data fields and code in the object. There
is no private fields or methods. It is simply not the assembly way.
## Example of object definition with inheritance.
[!1:_images/catdog.png][Fig.1 Inheritance]
In the following example can be seen all the above syntax in practice. The
type `TAnimal` defines several common data fields, the parameter `.Energy`
that is read-only and gives the current kinetic energy of the animal and the
abstract method `.Jump` that is not implemented for TAnimal, as long as the
different animals jumps differently and need special implementation.
The children types `TCat` and `TDog` implements their own methods `.Jump`.
;begin fasm
object TAnimal
.length dd ?
.height dd ?
.weight dd ?
.speed dd ?
param .Energy, .GetEnergy, NONE
method .GetEnergy
abstract .Jump, .height
endobj
object TCat, TAnimal
method .Jump, .height
endobj
object TDog, TAnimal
method .Jump, .height
endobj
method TAnimal.GetEnergy
begin
push ecx
mov ecx, [.self]
mov eax, [ecx+TAnimal.speed]
imul eax, eax
imul eax, [ecx+TAnimal.weight]
sar eax, 1 ; E = m.v^2/2
pop ecx
return
endp
method TCat.Jump
begin
; code that makes the cat jump not as other animals.
return
endp
method TDog.Jump
begin
; code that makes the dog jump not as other animals.
return
endp
;end
## Object manipulation macros.
### Creating objects
[#create] `create` macro
Once the object is defined, the user can create object instances, using the
macro instruction `create`. The syntax is:
;begin fasm
create DST, TYPE
;end
The macro allocates memory for the object instance, fills needed fields and
executes the method Create if such is defined for the given object type.
`DST` is the destination where we want the pointer to the object instance to
be stored. Can be register or memory location. Same as for `mov` instruction.
`TYPE` is an object type, previously defined with `object` macro.
### Destroy object.
[#destroy] `destroy` macro
The allocated object instance must be destroyed when not needed with the macro
instruction `destroy`. The syntax is:
;begin fasm
destroy SRC
;end
`SRC` is a pointer to the object instance. Can be register or memory content.
The macro will first call the Destroy method of the object if such is defined
and then will free the allocated dynamic memory.
### Set/Get object parameters.
[#get] `get` macro
[#set] `set` macro
The value of object parameter can be get with the macro `get`. The syntax is:
;begin fasm
get DST, PTR_OBJ, TYPE:PARAM
;end
The macro gets the value of `TYPE:PARAM` parameter of the object `PTR_OBJ` and
store it in `DST`.
`DST` and `PTR_OBJ` can be register or memory location, TYPE must be already
defined object type and PARAM parameter, defined in this object or any of its
predecessors.
Notice, the `TYPE` and `PARAM` must be separated by colon ":", not a dot.
The value of object parameter can be set to new value with the macto `set`.
The syntax is similar to the previous, only in different order:
;begin fasm
set PTR_OBJ, TYPE:PARAM, VALUE
;end
`PTR_OBJ` is the object which parameter have to be set.
`TYPE:PARAM` specifies the parameter name.
`VALUE` is the new value of the parameter.
### Executing object methods.
[#exec] `exec` macro
The macro instruction `exec` executes some object method. The syntax is:
;begin fasm
exec PTR_OBJ, TYPE:METHOD, [ARG]
;end
The macros has various count of arguments, depending on the arguments the
method accepts.
`TYPE:METHOD` must be valid combination of defined object type and method
name, separated by colon ":".
### Check object type
[#istype] `istype` macro
The user can check whether the object belongs to some type by using "istype"
macro instruction:
;begin fasm
istype OBJECT, TYPE
;end
This macro returns ZF flag set if the object belongs to the type or ZF cleared
if not. It will not change any registers.
For example, see following code:
;begin fasm
create eax, TCat ; create object instance.
istype eax, TCat
je .yes_cat ; ZF=1 It is a TCat...
int3
.yes_cat:
istype eax, TAnimal
je .yes_animal ; ZF=1 ...also, it is TAnimal...
int3
.yes_animal:
istype eax, TDog
je .yes_dog ; ZF=0 ...but is it NOT TDog.
int3 ; will stop here
.yes_dog:
;end
## Polymorphism
Polymorphism is one of the main properties of the OOP. It is the ability of
the object to execute different code on the same method call, depending on its
type.
[!2:_images/poly.png][Fig.2 Polymorphism]
In the context of our library, as long as the types inherit all the methods of
its parents and can redefine it, it means, that in the above example, `TCat`
and `TDog` both have method `.Jump`, inherited from `TAnimal`. (In this sense,
they are both of type `TAnimal`), but the implementation of `TCat.Jump` and
`TDog.Jump` differs.
This way, we can use the same code to process both types.
;begin fasm
create eax, TCat
create ebx, TDog
exec eax, TAnimal:Jump, 100
exec ebx, TAnimal:Jump, 100
;end
You can see, that the same code will call in the first case `TCat.Jump` and in
the second case `TDog.Jump` methods.