Fresh IDE . Artifact [9ee9e6af3f]
Not logged in

This repository is a mirror!

The original is located on: https://fresh.flatassembler.net/fossil/repo/fresh
If you want to follow the project, please update your remote-url

Artifact 9ee9e6af3f45c2a2b6211bda9850014bee8a571f:


# 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.