Prof Abimbola Olowofoyeku wrote:
On 19 Apr 2002 at 13:18, Frank Heckenbach wrote: [...]
That's not really what it did before. What I changed was to remove a (normally) redundant VMT pointer assignment. Usually the VMT pointer is assigned when the variable is created (i.e., at program/routine start for non-pointer objects, and after memory allocation when using `New').
Until recently, GPC *also* assigned the VMT when calling a constructor which is therefore redundant (especially when calling a constructor within `New', one could see two assignments next to each other which made it clear that one was redundant).
Pardon my ignorance - but shouldn't we assign the VMT when a constructor is called? It seems that, unless this is done, one cannot guarantee that the assignment has taken place.
Yes, we can (under normal conditions), since it happens whenever the object starts to exist (i.e., at program start, routine start or after memory allocation for global, local, and dynamic variables, respectively).
These things may look somewhat different to someone who's familiar with GPC's internals than someone who's not. Within GPC, there's a function (init_any) which is called exactly in those situations mentioned above, and which does all necessary initializations (currently for strings, schemata, files and objects). So objects are nothing special from this point of view.
In BP things are somewhat different: It doesn't have schemata, its strings don't store their capacity (which has some disadvantages), and for files they use a combination of "magic" values (which reduces the probability of finding a valid value in an uninitialized variable to 3/65536 under random conditions) and an `Assign' procedure which initializes and completely overwrites the file variable (which has some drawbacks, e.g. that re-assigning an already opened file leaves the file handle and the buffered data in the wild; that files must be assigned (i.e., no internal files possible); and that a coding mistake (forgetting to assign) can fail (i.e., accidentally use another existing file rather than causing a proper error) with a chance of 3/65536).
This leaves objects as something special in BP. (One might guess what they would have done if OOP had not been introduced as a later add-on, but had been present in the initial design. Maybe they'd also have done a general initialization concept, including files ...) BP also does some other strange things with constructors (IIRC, the memory allocation when calling a constructor within `New', is done from *within* the constructor (i.e., the object "allocates itself"); I had looked at the generated code when I used BP, and except for some extra complexity, I didn't seem to find any point in it -- which was confirmed when I later found out that it's not necessary in GPC while providing effectively the same functionality).
What GPC does seems much more logical to me: It allocates the memory, initializes the new variable (like it initializes strings, schemata and files), and then calls the constructor.
BP also has another strangeness, in that objects that have neither constructors nor destructors nor virtual methods don't have a VMT at all. This has some strange effects, e.g. since `SizeOf' reads the size from the VMT (if the type has one), applying `SizeOf' to an unintialized object that has neither of these things works, but stops working if you, say, add a (completely unrelated) virtual method (for another strange effect see the example below). These effects are probably not intentional, but they indicate that the concept might not be really good ...
So in GPC every object has a VMT, and therefore has to initialize the VMT pointer on creation to be compatible to BP in some reasonable cases (i.e., applying `SizeOf' to an object which has no constructor -- which works in BP if it also has no destructor and virtual method, as described above).
To sum up, when a constructor is called, the VMT pointer has already been set under normal conditions. It might not hurt to set it again, but it would not really solve any problem, either, since in `GetMem' situations, object fields of string, schema, etc. type would still remain uninitialized. Currently, in such a situation, one can do it all manually (with `SetType' for objects, and some more or less dirty tricks to set the discriminants). An initialize-any-variable (name?) builtin procedure as I suggested would seem like a better solution to this problem. (Though I'm still not sure why this problem arises at all -- I suppose to be bug-compatible to BP's lack of support for variables of dynamic size!?)
program Blah;
type pa = ^a; a = object f: Integer; end;
pb = ^b; b = object (a) g: Integer; end;
var v: pa;
begin v := New (pb); if SizeOf (v^) = SizeOf (b) then WriteLn ('OK') else if SizeOf (v^) = SizeOf (a) then WriteLn ('failed: size of a') else WriteLn ('failed: yet another size') end.
Frank