Subsections

- 1 Declaration
- 2 Fields
- 3 Constructors and destructors
- 4 Methods
- 5 Method invocation
- 6 Visibility

#
4 Objects

# 1 Declaration

Free Pascal supports object oriented programming. In fact, most of the compiler is written using objects. Here we present some technical questions regarding object oriented programming in Free Pascal. Objects should be treated as a special kind of record. The record contains all the fields that are declared in the objects definition, and pointers to the methods that are associated to the objects' type.

An object is declared just as a record would be declared; except that now,procedures and functions can be declared as if they were part of the record. Objects can ''inherit'' fields and methods from ''parent'' objects. This means that these fields and methods can be used as if they were included in the objects declared as a ''child'' object.

Furthermore, a concept of visibility is introduced: fields, procedures and functions can be delcared as `public` or `private`. By default, fields and methods are `public`, and are exported outside the current unit. Fields or methods that are declared `private` are only accessible in the current unit. The prototype declaration of an object is as follows:

> object types

As can be seen, as many `private` and `public` blocks as needed can be declared. `Method definitions` are normal function or procedure declarations. Fields cannot be declared after methods in the same block, i.e. the following will generate an error when compiling:

    Type MyObj = Object
           Procedure Doit;
           Field : Longint;
         end;

But the following will be accepted:

    Type MyObj = Object
          Public
           Procedure Doit;
          Private
           Field : Longint;
         end;

because the field is in a different section.

Remark: Free Pascal also supports the packed object. This is the same as an object, only the elements (fields) of the object are byte-aligned, just as in the packed record. The declaration of a packed object is similar to the declaration of a packed record :

    Type
      TObj = packed object;
       Constructor init;
       ...
       end;
      Pobj = ^TObj;
    Var PP : Pobj;

Similarly, the `{$PackRecords }` directive acts on objects as well.

# 2 Fields

Object Fields are like record fields. They are accessed in the same way as a record field would be accessed : by using a qualified identifier. Given the following declaration:

    Type TAnObject = Object
           AField : Longint;
           Procedure AMethod;
           end;
    Var AnObject : TAnObject;

then the following would be a valid assignment:

      AnObject.AField := 0;

Inside methods, fields can be accessed using the short identifier:

    Procedure TAnObject.AMethod;
    begin
      ...
      AField := 0;
      ...
    end;

Or, one can use the `self` identifier. The `self` identifier refers to the current instance of the object:

    Procedure TAnObject.AMethod;
    begin
      ...
      Self.AField := 0;
      ...
    end;

One cannot access fields that are in a private section of an object from outside the objects' methods. If this is attempted anyway, the compiler will complain about an unknown identifier. It is also possible to use the `with` statement with an object instance:

    With AnObject do
      begin
      Afield := 12;
      AMethod;
      end;

In this example, between the `begin` and `end`, it is as if `AnObject` was prepended to the `Afield` and `Amethod` identifiers. More about this in section With

#
3 Constructors and destructors

As can be seen in the syntax diagram for an object declaration, Free Pascal supports constructors and destructors. The programmer is responsible for calling the constructor and the destructor explicitly when using objects. The declaration of a constructor or destructor is as follows:

> Constructors and destructors

A constructor/destructor pair is required if the object uses virtual methods. In the declaration of the object type, a simple identifier should be used for the name of the constuctor or destructor. When the constructor or destructor is implemented, A qualified method identifier should be used, i.e. an identifier of the form `objectidentifier.methodidentifier`. Free Pascal supports also the extended syntax of the `New` and `Dispose` procedures. In case a dynamic variable of an object type must be allocated the constructor's name can be specified in the call to `New`. The `New` is implemented as a function which returns a pointer to the instantiated object. Consider the following declarations:

    Type
      TObj = object;
       Constructor init;
       ...
       end;
      Pobj = ^TObj;
    Var PP : Pobj;

Then the following 3 calls are equivalent:

     pp := new (Pobj,Init);

and

      new(pp,init);

and also

      new (pp);
      pp^.init;

In the last case, the compiler will issue a warning that the extended syntax of `new` and `dispose` must be used to generate instances of an object. It is possible to ignore this warning, but it's better programming practice to use the extended syntax to create instances of an object. Similarly, the `Dispose` procedure accepts the name of a destructor. The destructor will then be called, before removing the object from the heap.

In view of the compiler warning remark, the following chapter presents the Delphi approach to object-oriented programming, and may be considered a more natural way of object-oriented programming.

# 4 Methods

Object methods are just like ordinary procedures or functions, only they have an implicit extra parameter : `self`. Self points to the object with which the method was invoked. When implementing methods, the fully qualified identifier must be given in the function header. When declaring methods, a normal identifier must be given.

# 5 Method invocation

Methods are called just as normal procedures are called, only they have an object instance identifier prepended to them (see also chapter Statements). To determine which method is called, it is necessary to know the type of the method. We treat the different types in what follows.

### 1 Static methods

Static methods are methods that have been declared without a `abstract` or `virtual` keyword. When calling a static method, the declared (i.e. compile time) method of the object is used. For example, consider the following declarations:

    Type
      TParent = Object
        ...
        procedure Doit;
        ...
        end;
      PParent = ^TParent;
      TChild = Object(TParent)
        ...
        procedure Doit;
        ...
        end;
      PChild = ^TChild;

As it is visible, both the parent and child objects have a method called `Doit`. Consider now the following declarations and calls:

    Var ParentA,ParentB : PParent;
        Child           : PChild;
       ParentA := New(PParent,Init);
       ParentB := New(PChild,Init);
       Child := New(PChild,Init);
       ParentA^.Doit;
       ParentB^.Doit;
       Child^.Doit;

Of the three invocations of `Doit`, only the last one will call `TChild.Doit`, the other two calls will call `TParent.Doit`. This is because for static methods, the compiler determines at compile time which method should be called. Since `ParentB` is of type `TParent`, the compiler decides that it must be called with `TParent.Doit`, even though it will be created as a `TChild`. There may be times when the method that is actually called should depend on the actual type of the object at run-time. If so, the method cannot be a static method, but must be a virtual method.

### 2 Virtual methods

To remedy the situation in the previous section, `virtual` methods are created. This is simply done by appending the method declaration with the `virtual` modifier. Going back to the previous example, consider the following alternative declaration:

    Type
      TParent = Object
        ...
        procedure Doit;virtual;
        ...
        end;
      PParent = ^TParent;
      TChild = Object(TParent)
        ...
        procedure Doit;virtual;
        ...
        end;
      PChild = ^TChild;

As it is visible, both the parent and child objects have a method called `Doit`. Consider now the following declarations and calls :

    Var ParentA,ParentB : PParent;
        Child           : PChild;
       ParentA := New(PParent,Init);
       ParentB := New(PChild,Init);
       Child := New(PChild,Init);
       ParentA^.Doit;
       ParentB^.Doit;
       Child^.Doit;

Now, different methods will be called, depending on the actual run-time type of the object. For `ParentA`, nothing changes, since it is created as a `TParent` instance. For `Child`, the situation also doesn't change: it is again created as an instance of `TChild`. For `ParentB` however, the situation does change: Even though it was declared as a `TParent`, it is created as an instance of `TChild`. Now, when the program runs, before calling `Doit`, the program checks what the actual type of `ParentB` is, and only then decides which method must be called. Seeing that `ParentB` is of type `TChild`, `TChild.Doit` will be called. The code for this run-time checking of the actual type of an object is inserted by the compiler at compile time. The `TChild.Doit` is said to override the `TParent.Doit`. It is possible to acces the `TParent.Doit` from within the varTChild.Doit, with the `inherited` keyword:

    Procedure TChild.Doit;
    begin
      inherited Doit;
      ...
    end;

In the above example, when `TChild.Doit` is called, the first thing it does is call `TParent.Doit`. The inherited keyword cannot be used in static methods, only on virtual methods.

### 3 Abstract methods

An abstract method is a special kind of virtual method. A method can not be abstract if it is not virtual (this is not obvious from the syntax diagram). An instance of an object that has an abstract method cannot be created directly. The reason is obvious: there is no method where the compiler could jump to ! A method that is declared `abstract` does not have an implementation for this method. It is up to inherited objects to override and implement this method. Continuing our example, take a look at this:

    Type
      TParent = Object
        ...
        procedure Doit;virtual;abstract;
        ...
        end;
      PParent=^TParent;
      TChild = Object(TParent)
        ...
        procedure Doit;virtual;
        ...
        end;
      PChild = ^TChild;

As it is visible, both the parent and child objects have a method called `Doit`. Consider now the following declarations and calls :

    Var ParentA,ParentB : PParent;
        Child           : PChild;
       ParentA := New(PParent,Init);
       ParentB := New(PChild,Init);
       Child := New(PChild,Init);
       ParentA^.Doit;
       ParentB^.Doit;
       Child^.Doit;

First of all, Line 3 will generate a compiler error, stating that one cannot generate instances of objects with abstract methods: The compiler has detected that `PParent` points to an object which has an abstract method. Commenting line 3 would allow compilation of the program.

Remark: If an abstract method is overridden, The parent method cannot be called with `inherited`, since there is no parent method; The compiler will detect this, and complain about it, like this:

    testo.pp(32,3) Error: Abstract methods can't be called directly

If, through some mechanism, an abstract method is called at run-time, then a run-time error will occur. (run-time error 211, to be precise)

# 6 Visibility

For objects, 3 visibility specifiers exist : `private`, `protected` and `public`. If a visibility specifier is not specified, `public` is assumed. Both methods and fields can be hidden from a programmer by putting them in a `private` section. The exact visibility rule is as follows:

Private
  All fields and methods that are in a `private` block, can only be accessed in the module (i.e. unit or program) that contains the object definition. They can be accessed from inside the object's methods or from outside them e.g. from other objects' methods, or global functions.
Protected
  Is the same as `Private`, except that the members of a `Protected` section are also accessible to descendent types, even if they are implemented in other modules.
Public
  sections are always accessible, from everywhere. Fields and metods in a `public` section behave as though they were part of an ordinary `record` type.