11.3 Formal declaration

Object Pascal has the concept of Forward declarations. Objective-C takes this concept a bit further: it allows to declare a class which is defined in another unit. This has been dubbed “Formal declaration” in Objective-Pascal. Looking at the syntax diagram, the following is a valid declaration:

MyExternalClass = objcclass external;

This is a formal declaration. It tells the compiler that MyExternalClass is an Objective-C class type, but that there is no declaration of the class members. The type can be used in the remainder of the unit, but its use is restricted to storage allocation (in a field or method parameter definition) and assignment (much like a pointer).

As soon as the class definition is encountered, the compiler can enforce type compatibility.

The following unit uses a formal declaration:

unit ContainerClass;

{$mode objfpc}
{$modeswitch objectivec1}

interface

type
  MyItemClass = objcclass external;

  MyContainerClass = objcclass
    private
     item: MyItemClass;
    public
     function getItem: MyItemClass; message 'getItem';
  end;

implementation

function MyContainerClass.getItem: MyItemClass;
begin
  result:=item; // Assignment is OK.
end;

end.

A second unit can contain the actual class declaration:

unit ItemClass;

{$mode objfpc}
{$modeswitch objectivec1}

interface

type
  MyItemClass = objcclass(NSObject)
  private
    content : longint;
  public
    function initWithContent(c: longint): MyItemClass;
       message 'initWithContent:';
     function getContent: longint;
       message 'getContent';
  end;

implementation

function MyItemClass.initWithContent(c: longint):
   MyItemClass;
begin
  content:=c;
  result:=self;
end;

function MyItemClass.getContent: longint;
begin
  result:=content;
end;

end.

If both units are used in a program, the compiler knows what the class is and can verify the correctness of some assignments:

Program test;

{$mode objfpc}
{$modeswitch objectivec1}

uses
  ItemClass, ContainerClass;

var
  c: MyContainerClass;
  l: longint;
begin
  c:=MyContainerClass.alloc.init;
  l:=c.getItem.getContent;
end.