OOP (Was: bpcompat-1.0.zip)_(re)

Mon, 26 May 1997 18:39:22 -0400 (EDT)


On Mon, 26 May 1997, Peter Gerwinski wrote:

> I agree, but not every constructor call does actually initialize an
> object.  Since it is difficult to be sure whether an object already is
> initialized or not, we have to decide about this when the constructor
> is *called*.  For this reason, it happened to be easier to do the
> initialization outside the constructor's body.

Yes, you're right, the constructor calls that comes from calling the
inherited constructor must not initialize the object... In BP, the two
hidden parameters to constructors are the instance pointer (the Self
parameter) and the VMT offset of the object that is being constructed. If
the VMT offset given is the same as the called constructor, then it is the
first constructor called and the object is initialized. If the VMT
parameter isn't the same as the called constructor, it is because it is
being called from within another constructor and hence the object is
already initialized. This is actually easy! ;-)

> Look whether the VMT field contains a nonzero value.  To be absolutely
> sure, we can even check whether the pointer really points to a VMT: The
> first Word pointed to must be a positive Integer (the size of the object),
> the second one its negative (which is included for purposes like this
> one).  Problem:  This will only work if the object was pre-initialized
> to have a zero VMT field.  This can be achieved with `New', but not with
> `GetMem', so you have still to be careful when implementing streams.

Here. A check in the constructor would not be reliable, since the memory
could have been allocated with GetMem (and we have *no* mean to check this
out) and the VMT field is filled with random bytes in that case, which
could very well be an actual valid VMT pointer (with *some* luck, if the
area of memory has already been allocated to another object, the chances
are high that there is a valid VMT pointer there!).

> > In BP it cannot. It *must* be a constructor, because this is relied upon
> > by TStream.Get to initialize the object VMT link correctly and allocate
> > the correct amount of memory.
> 
> It could be in BP too, if we changed the `tStream' object.  Just do
> everything, the constructor would normally do, by hand.

We cannot change BP! I mean, the idea of the BPCOMPAT package is to be
compatible with BP, not make BP GPC compatible! :-)

> > I am doing a BP compatible StreamRec facility for the BPCOMPAT package.
> 
> Great!  }:-=)=  (* This shall be a smiling Gnu. :*)

This one is going to be a cheap clone 100% compatible (well, compatible
interface). But there will be a "good" one made just for GPC soon...

> > Are we looking for BP compatibility or not?
> 
> We are in part.  The primary goal of GPC is to produce the best Pascal
> compiler the world has ever seen.  (See the Info documentation for
> details.)  BP compatibility is desireable because (ii) BP is not too
> bad and (i) many BP programmers will try GPC only if they can use their
> existing programs without any change.

I meant in the BPCOMPAT... ;-)

> > BTW, I *am* also developing a
> > class library made just for GPC using all the new features and fixing many
> > of the problems with the BP OBJECTS.PAS and the TurboVision libraries.
> 
> :-)

Hence, I am not putting a lot of effort to enhance BPCOMPAT units, only
fixing them so they work correctly.

> > It would be nice to have RTL functions to get an object name and parent,
> > a bit like Delphi can give you the class name of an object.
> 
> How does Delphi do this?  (Sorry for the stupid question, but my
> experience with Delphi is very limited, primarily because I cannot stand
> the mouse-only "user interface".)

Delphi does this by having methods in *every* objects that are provided by
the compiler that returns the name of the objects and their parent.

> What about making the structure of the VMT record visible for the program?
> For instance a built-in
> 
>     Type
>       VmtRec = record
>         Size, NegSize: Integer;
>         VirtualMethod: array [ 0..1 ] of Pointer;
>       end (* VmtRec *);
> 
> Where the `1' above stands for the unknown number of methods in a VMT.
> 
> (* I thought about changing the VMT to a schema type
> 
>     Type
>       VmtRec ( n: Integer ) = record
>         Size, NegSize: Integer;
>         VirtualMethod: array [ 1..n ] of Pointer;
>       end (* VmtRec *);
> 
> which would place `n' as an additional field at the very beginning of
> each VMT.  But it's probably better to let `Size' stay the first field and
> to save the additional storage for the number of methods in the object. *)

This doesn't give much information about the object apart from its size
and the number of methods and where they are... What we'd need is
something like from which class is another class derived from, its name,
and so on...

> > And also not put all the symbols in every programs, just those that use
> > the "ClassName()" function,
> 
> Difficult.

Hmm... Is it possible to have a function automatically generated by the
compiler before going to the optimizing stage? It would contain a table
translating VMT pointers into strings of the classes name and would be
optimized out of the program by the optimizer if unused, right?

> > A unique number is a bad idea and shouldn't be used. They can change and
> > invalidate a file containing streamed objects from compile to compile.
> 
> That's what I meant with the "how to choose" problem.  When deriving it
> from the name in an unambiguous way, it would work.  But how would that
> "unambiguous way" look like?  A CRTC check sum?  (I don't really know
> what that is ...;)

CRC (Cyclic Redundancy Check) you must mean. It is an error detection
scheme too often used as a hash key generator (which it isn't, it
collides a bit too often).

> > The way I see it, the best way is to make a legal way to directly call a
> > specific class constructor. Like the "typed new()" function (passing an
> > object type as the first parameter) does, but being able to put a variable
> > there. Maybe a GPC-specific new() function?
> 
> `New' already is as GPC-specific as it could be ...
> 
> > With another name of course to
> > avoid incompatibilities...
> 
> I will think about that and let you know if I have an idea.

What I mean is (for example) a NewObject() function that would work just
like New(), but instead of a typed pointer or an object type itself, it
would take a VMT pointer as the first parameter. It would make the
construction of an object from a stream as simple as calling
"Get:=NewObject(TStreamRec.VMTLink, Load(@Self));" at the end of the 
TStream.Get method.

BTW, how does New() work when it is passed an object type (say, PObject) 
as the first parameter?

Pierre Phaneuf

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


Pierre Phaneuf (pp@dilu.ml.org)

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