bpcompat-1.0.zip_(re)

Fri, 23 May 1997 12:01:53 -0400 (EDT)


On Fri, 23 May 1997, Peter Gerwinski wrote:

> >From the announcement of gpc-970510:
> 
>   * `TypeOf' applied to object variables works now, too.  As a GPC extension,
>     you can explicitly assign a value to "TypeOf ( MyObj )" if extended syntax
>     is ON (*$X+*).
> 
> This means that, with (*$X+*), you can explicitly assign a `TypeOf' to
> an object.  I implemented this extension just for the purpose to write the
> `tStream.Get' method.  (In BP, this is achieved with assembler, but we want
> to have it portable for GPC.)

I actually had it done without assembler in BP in a compatible manner (in
my own version of the stream system), but still incompatible.

> > Something that would enable me to do something so that
> > new(typeof(TMyObject), Init) creates an instance of TMyObject, calls Init
> > and returns a pointer to the newly created object would be just *perfect*.
> 
> Please add it to `objects.pas'!  My suggestion:
> 
> 1) Write a `RegisterType' function, so you can read the `ObjType' out of
>    the stream and look up its `VmtLink'.
> 
> 2) Replace the `New' in `tStream.Get' by a `GetMem' with the Size read off
>    the VMT (a Word variable at the very beginning of the VMT).

Ah, I didn't knew the size was at the beginning of the VMT... But this
isn't quite the Right Way (if the VMT format changes for whatever reason),
no?

> 3) Explicitly assign `VmtLink' to `TypeOf ( the new object )'.
> 
> 4) Call the object's `Load' constructor.

This could cause problems. How shall I call the Load constructor?

function CreateObject(VMTLink: pointer; S: PStream): PObject;
var
    P: PObject;
    Size: ^word;
begin
    Size:=VMTLink;
    getmem(P, Size^);
    TypeOf(P):=VMTLink;
    P^.Load(S);
end;

This wouldn't work (in BP at least), since this will call TObject's Load
constructor and it will reset the type of the object to TObject, whatever
has been set with TypeOf().

On the other hand, if I call it using a pointer to the Load constructor
(so that I get the right constructor), I don't even have to set the
TypeOf() of the object, since it is set by the constructor itself (like in
BP), but I have to do the method call by hand, just like the assembler
part in the Borland OBJECTS.PAS or my no-assembler solution (which looked 
like the following and is just as dependent on compilers internals).

type
    TLoadConstructor = function(S: PStream;
				VMTOffset: word;
				ASelf: pointer): pointer;

(I'm not quite that sure about the parameter order, it is important)

Then I called the constructor like this:

P:=TLoadConstructor(LoadPtr^)(S, ofs(VMTLink), nil);

The "nil" for self causes the constructor to allocate the right amount of
memory for the object before calling the constructor. The pointer to the
object instance is returned by the function. Note that this produces
almost the same code (in BP) as a new() function call, but this is
extremely dependent on the compilers internals!

I guess that we cannot extend new() so that passing it a VMT pointer would
make it instantiate the correct object type and call the right
constructor, but how does it work when it gets PObject as a first
parameter? Maybe some meta-function that returns the type itself? ;-)

What do you think?

"The use of COBOL cripples the mind; its teaching should, therefore, be
regarded as a criminal offense." - Edsger W. Dijkstra.


Pierre Phaneuf (pp@55-174.hy.cgocable.ca)

HTML conversion by Lluís de Yzaguirre i Maura
Institut de Lingüística Aplicada - Universitat "Pompeu Fabra"
e-mail: de_yza@upf.es