OOP_(re)

Mon, 26 May 1997 20:09:51 -0400 (EDT)


On Mon, 26 May 1997, Frank Heckenbach wrote:

> Bottom line: I don't think it can be done all automatically, but it can be
> done much more comfortably to the programmer than in TV.

I agree with you. I am in effect creating a better way to do it, but it
will NOT be in BPCOMPAT. I'm a proficient user of TV, and I'll try to have
the object parts of the BPCOMPAT package as compatible with it as
possible... It *will* be in a GPC-specific class library of mine I'll
contribute to the GPC team "When It's Ready (TM)", of course! ;-)

> type MyObject(TObject)
>        Const ObjID:Word = MyBaseID+42;
>        ...
>      End;
> 
> or ... why not also
> 
>        Const ObjID:Word = Inherited ObjID+1;
> 
> (Though the simple "+1" might not be good, as it can easily lead to
> conflicts - but perhaps something similar.)
> 
> Concerning the numbering convention, I'd also suggest something "better" than
> TV's way, perhaps an ID consisting of 4 parts (perhaps 16 bits for each part,
> this would leave room for a growing number of programs for some time (well -
> at least as long as 640 KB are enough for everybody... ;-), and the whole
> thing would be 64 bits (longlongint?)):
> 
> 1. "unique" programmer ID
> 2. ID for a "category" of types (graphical objects, mathematical objects,
>      dialog elements, ...) - unique only for the programmer
> 3. ID for a certain type within a category
> 4. "version number" for the type (i.e., if the fields or their semantics
>    change, the version number will be changed, too, so that old objects in
>    streams can be recognized)

All this is not really needed in a system similar to TV, since you can
register the objects yourself in case of conflict, resolving them to your
liking. Though it is a nice idea to have a programmer/vendor part... A
call to a unit-specific RegisterType procedure could look like this: 
RegisterObjects(1), the 1 being a value selected by the application
programmer to prevent conflicts with another unit. How about a dword, with
the first 16 bits for the unit ID and the last 16 bits for the object ID
itself within the unit. Gives you 64K units in a single program with 64K
objects per unit... Should be quite enough! :-)

The version number isn't a good idea though... The idea with the object ID
is to spawn the correct object to load the object from the stream. The
correct way to put versioning in your streamable classes is to have a
version number stored at the beginning of your object by your Store
method, and have your Load method have a 'case' statement that loads the
object correctly according to the various versions.

> As I said above, I wouldn't like this. But it could be an idea to have
> ObjID be a string instead of a numerical value. But I'm not sure if it's
> worth the additional work required...

Not really IMHO... I agree with you on this subject...

> Perhaps it's easier to let "ClassName" be a normal object constant (if
> they'll be implemented). Then the programmer could decide which names to
> include in the program and how to call them (e.g. the actual identifier
> might be "TSomething", but for the ClassName it might be preferable to
> have just "Something").

The idea with having a separate ClassName() function is to let you have a
ClassName method, variable or constant without losing the functionality.

> > 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? With another name of course to
> > avoid incompatibilities...
>  
> This would require something like "virtual constructors", wouldn't it?
> I.e., the constructors would have to have the same parameters in all
> classes, and their addresses would be stored in the VMT. Doesn't seem
> impossible, perhaps it's the most logical thing to do.

No... You know that New() works either this way: New(P, Init), where P is
a typed pointer (of an object type that has a Init constructor, of
course!), where P will be changed to point to the new instance or set as
nil if the object didn't construct correctly. The other way is as a
function that work like this: P:=New(PObject, Init), which will construct
a TObject and return the instance pointer (or nil). It isn't a virtual
constructor, you simply choose which object to construct.

> > We are in part.  The primary goal of GPC is to produce the best Pascal
> > compiler the world has ever seen.
> 
> I agree with Peter. I, FWIW, didn't use TV -- partly because some parts
> of it (including class registration) were, IMHO, badly implemented.
> If gpc's TV would be the same, I probably wouldn't use it, either.

Yes, I agree, but let's keep in mind what we're looking to fix in this
thread is the BPCOMPAT package, which will have to look like BP libraries
are, at least on the outside. BTW, what didn't you like exactly with TV?
As for the class registration, what I didn't like was that it used the
data segment, which isn't a very clean hack IMHO... Apart from that, it's
ok by me (the class registration system!). The Free method is one of the
purest evils in there. :-) (and it is in the BPCOMPAT package!)

> So we may need both: a "100% BP compatible" unit for quick changes, and
> a "better" gpc unit to which programs can be converted afterwards, and
> which new programs can use from the beginning. Actually, I think, the
> changes needed for BP programs shouldn't be too big: make the "Load"
> constructor virtual (if we do it this way), declare the "ObjID" constant,
> and remove the registration stuff. Could even be simplified with some
> "IFDEF"s and clever use of the preprocessor, I guess.

I'm developing something here for a "GPC enhanced" class library, I'll
keep you posted! Up to now, no compiler changes or new features are
needed, except for a clean way to spawn an object from its VMT link. I
started developing it with BP so I knew exactly how to do it (it is
portable, if you don't count the heck of limitations induced by BP
(collections are limited to about 16K elements with BP, where they are
"big enough" with GPC) ). I "faked" the 'typed New()' code using Turbo
Debugger to learn how it worked...

> A "Parent" field in the VMT seems quite useful to me. Also, a list of the
> childs (this would require a "FirstChild", and a "Sibling" field in each
> VMT). And perhaps they could be accessed through the VmtRec as well as
> as normal object constants...

At least Parent would be useful. Note that my class library registration
system has a field for the parent object and can walk the registration
list to find its childs.

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