According to Frank Heckenbach:
Though the VMT format might not be likely to change, perhaps it would be better to have a built-in function of the compiler to return the object size of a given VMT link (should be easy to implement).
It's easy to implement as a function: Let `pObject' be a pointer to the parent object `tObject'of all `Stream'able objects, then
(*$X+*) (* For hackers, only *)
Function ObjectSizeInBytes ( VmtLink: Pointer ): Word;
Var O: tObject;
begin TypeOf ( O ):= VmtLink; (* Initialize it manually *) ObjectSizeInBytes:= SizeOf ( O ); end.
According to Pierre Phaneuf:
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().
In GNU Pascal, initialization takes place outside the constructor as some additional inline code. (I am not 100% sure that this will not change.)
But you are right - this does not work in the current GPC either. But I can modify GPC such that constructors only initialize an object if it has not been initialized previously. Then it will work, since assignment to `TypeOf ( something )' *is* (manual) initialization.
According to Frank Heckenbach:
Couldn't "Load" be a virtual method instead of a constructor (perhaps a Boolean function that returns if it didn't fail)?
Yes. IMHO, it could be in BP as well.
But if it's possible, you also wouldn't have to register the Load constructor (neither Store, of course), so the registration could also be simplified to something like RegisterType(ObjType, VMTLink:Word); and the programs that use this function don't have to declare a "StreamRec" manually, which would be another simplification.
Exactly. For compatibility's sake, somebody should implement the "StreamRec" stuff, too, but it can be done in an easier way.
And it would be even better if the compiler could do this automatically, i.e. each object type could (optionally) declare an "ObjType" value, and the compiler would provide functions to get the ObjType from a VMT link and vice versa.
Sounds nice, but how to find a unique number for each object? Derive it from the name? Then what about storing the name of the object itself in the Stream?
Thinking about how to implement this, I realize this is basically the same as object constants -- something that's missing in BP and I could've used sometimes. This could be a useful extension to BP's objects. (The constants and their values would be inherited if not redeclared, just like virtual methods.)
And they would be stored in the VMT. Sounds reasonable. And the compiler could (optionally?) provide an automatic "name" object constant and/or a unique number ...
[...]
Just some ideas...
Sounds good, but I think the "stabilization" of gpc-2.1 has higher priority. But this might be of interest for gpc-2.2 ...
Greetings,
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer peter.gerwinski@uni-essen.de - http://home.pages.de/~peter.gerwinski/ [970201] maintainer GNU Pascal [970510] - http://home.pages.de/~gnu-pascal/ [970125]
On Sun, 25 May 1997, Peter Gerwinski wrote:
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().
In GNU Pascal, initialization takes place outside the constructor as some additional inline code. (I am not 100% sure that this will not change.)
That's the problem (that you're not sure it will not change). BTW, the constructor *is* the logical place do to such a thing...
But you are right - this does not work in the current GPC either. But I can modify GPC such that constructors only initialize an object if it has not been initialized previously. Then it will work, since assignment to `TypeOf ( something )' *is* (manual) initialization.
But how do you check if an object is initialized or not? I don't think this is the best way either, unless you can devise a *sure* way to check out if the object is initialized.
Couldn't "Load" be a virtual method instead of a constructor (perhaps a Boolean function that returns if it didn't fail)?
Yes. IMHO, it could be in BP as well.
It could be in GPC, but is this a BP compatibility unit or not? ;-) 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.
Exactly. For compatibility's sake, somebody should implement the "StreamRec" stuff, too, but it can be done in an easier way.
I am doing a BP compatible StreamRec facility for the BPCOMPAT package.
And it would be even better if the compiler could do this automatically, i.e. each object type could (optionally) declare an "ObjType" value, and the compiler would provide functions to get the ObjType from a VMT link and vice versa.
Sounds nice, but how to find a unique number for each object? Derive it from the name? Then what about storing the name of the object itself in the Stream?
Are we looking for BP compatibility or not? 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. 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. A separate function would be better (probably something accepting a VMT pointer (as returned by TypeOf() ) as a parameter), since it wouldn't "use up" a method name. Would be important to put the names of the classes apart from the symbol table, since the program has to work even if it is stripped! And also not put all the symbols in every programs, just those that use the "ClassName()" function, optimizing those using constants as their parameter and so on...
And they would be stored in the VMT. Sounds reasonable. And the compiler could (optionally?) provide an automatic "name" object constant and/or a unique number ...
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. The name isn't also a good idea for a stream (for example, you can lose the TStrMaker/TStrList functionality). But the name could be useful for other things...
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...
Pierre Phaneuf
"The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offense." - Edsger W. Dijkstra.