Forward defined types (and object

Gale Paeper gpaeper at empirenet.com
Fri Jul 8 04:27:24 CEST 2005


Frank Heckenbach wrote:
> 
> Gale Paeper wrote:
> 
[snip]
> > The forward object type declaration must have a complete type
> > declaration in the same type declaration part (like Pascal's requirement
> > for pointer types).  The commented out var declaration part and type
> > keyword is what I used to test that requirement. Uncomment that part and
> > you get:
> >
> > Error   : unresolved forward class reference to 'objA'
> > ForwardObjectTest.p line 11   var
> 
> Good (in accordance with OOE, except for the syntax).

The other part of OOE's deferred class requirement (i.e., "cannot be
used in a class-inheritance-list before its complete definition is
specified") is also enforced.  A slight modification of the test program
I've been using for an example:

program ForwardObjectTest1;

type	
  objA = object; forward;
  objB = object
    {...}
    o : objA; { objB uses objA }
    {...}
  end;

  { WRONG - Can't inherit from a FORWARD declared object }
{ objC = object(objA)
    
  end;  
}  
  objA = object
    {...}
    p : objB; { objB uses objA }
    {...}
  end;  

  { OK - Can inherit from a FORWARD object after it is fully defined }
  objD = object(objA)
    { objD inherits from objA }
  end;  
     
begin
end.

With the objC type declaration commented out the program compiles
without error.  Uncomment the objC type declaration and you get the
follow compilation error with CodeWarrior Pascal:

Error   : class 'objA' was declared 'FORWARD' or 'EXTERNAL'
ForwardObjectTest1.p line 12   objC = object(objA)

For the sake of completeness and since the error message refers to
external object declarations, I suppose CodeWarrior Pascal and MPW
Pascal's support for external object declarations should be mentioned.

The basic purpose and reason for external object declaration is the same
as it is for forward declared objects except it is used for mutually
dependent object type declarations between unit interfaces.

Before an example program demonstrating the external object feature and
how it can be used, a few notes on this particular MacPascal Object
Pascal feature:

1.  I'm not sure any real world program actually makes use of it.

2.  Even Apple, who invented the feature for MPW Pascal, called code
using external objects "ugly" and the code, even though it maybe useful, confusing.

3.  It isn't the easiest feature to make use of.  It takes some thought
and care in organizing code to avoid circular unit interface dependency
errors and unresolved external object declaration errors.

So, there's no misunderstanding, I'm not asking for GPC's support for
MacPascal style objects to include external object declaration support. 
Put it in the "to be considered if someone really needs it" bin.  I'm
covering MacPascal external object declaration support so that Frank and
Waldek are at least aware of the feature and have an example of its usage.

The example program and units are:

program ExternalObjectTest;

uses UObjA, UObjB;
	
var
  ObjAInstance: ObjA;
  ObjBInstance: ObjB;

begin
	
	ObjAInstance := NewObjA;
	ObjBInstance := NewObjB;
	ObjAInstance.InitwithObjB(ObjBInstance);
	ObjBInstance.InitwithObjA(ObjAInstance);
	ObjAInstance.TestObjAsObjBReference;
	ObjBInstance.TestObjBsObjAReference;
	Dispose(ObjAInstance);
	Dispose(ObjBInstance);
end.

unit UObjA;

interface

type
  ObjB = object; external;
  ObjA = object
    fObjB: ObjB;
    procedure InitwithObjB(InitObj: ObjB);
    procedure TestObjAsObjBReference;
    procedure TestIt;
  end;
  
function NewObjA: ObjA; 

implementation

  uses UObjB;
  
  function NewObjA: ObjA;
  var
    obj: ObjA;
  begin
    new(obj);
    NewObjA := obj;
  end;
  
  procedure ObjA.InitwithObjB(InitObj: ObjB);
  begin
    fObjB := InitObj;
  end;

  procedure ObjA.TestObjAsObjBReference;
  begin
    writeln ('In ObjA calling fObjB');
    fObjB.TestIt;
  end;
  
  procedure ObjA.TestIt;
  begin
    writeln ('In ObjA TestIt');
  end;
  
end.

unit UObjB;

interface

  uses UObjA;
		
type
  ObjA = object; external;
  ObjB = object
    fObjA: ObjA;
    procedure InitwithObjA(InitObj: ObjA);
    procedure TestObjBsObjAReference;
    procedure TestIt;
  end;
 
function NewObjB: ObjB; 

implementation

  function NewObjB: ObjB;
  var
    obj: ObjB;
  begin
    new(obj);
    NewObjB := obj;
  end;

  procedure ObjB.InitwithObjA(InitObj: ObjA);
  begin
    fObjA := InitObj;
  end;

  procedure ObjB.TestObjBsObjAReference;
  begin
    writeln ('In ObjB calling fObjA');
    fObjA.TestIt;
  end;
  
  procedure ObjB.TestIt;
  begin
    writeln ('In ObjB TestIt');
  end;
  
end.

When compiled with CodeWarrior Pascal and subsequently ran, the program
output is:

In ObjA calling fObjB
In ObjB TestIt
In ObjB calling fObjA
In ObjA TestIt

Gale Paeper
gpaeper at empirenet.com




More information about the Gpc mailing list