[fpc-pascal] casting back a pointer to original type --> variable & value types

Andrew Hall andrew.hall at shaw.ca
Sun May 30 17:01:14 CEST 2010


On 30 May 10, at 04:00 , spir ☣ wrote:

> So, it seems the language knows (at runtime) about the real type of a *value*. I must declare element, the variable, with type C, since I do not know anything at coding time. But Pascal correctly calls C1.text, due to "virtual" & "override" modifiers. So, it means that the language has additional type information and uses it to make a distinction between variable and value types. Correct? Else, how can it correctly call C1.text?

Correct.  Each object instance has a pointer to a structure which defines its class - inheritance, TypeInfo, VMT (virtual method table), etc.  This allows the application access to everything about the instance variable at runtime.  Suggest reading the Class Types section of the Programmers Manual and anything related to Classes, VMT or TypeInfo in the Programmers, Run-Time Library and Language Reference Manuals.

> But I'm not 100% sure this means that, for Pascal and at runtime, element's value is of type C1. Is there a way to know value and/or variable's types, such as a func TypeName()?

All classes are derived from TObject which has many useful methods - including Classname, ClassnameIs(), ClassType and InheritsFrom().  It would be worth reading the TObject section of the Run-Time Library Manual.

> (Side-note: I do not understand why this overriding mechanism needs to be explicitely stated with a modifier keyword: when a programmer writes a specialised method on a sub-class, obviously s/he intends it to be called, no?)

Not necessarily.  Choosing between Static/Virtual allows the class designer to determine what aspects of the ancestor class behaviour can be modified in a descendent - and therefore protect the ancestor function from being accidentally or purposefully broken.  Usually only a few methods of a class need to be virtual.

In Delphi and FPC all methods are static by default (this is distinctly different from many other languages where methods are always virtual).  Static methods execute faster as the VMT does not need to be accessed, and they can be called against a nil object.  Static methods also allow parameters to vary between classes (this constraint can be very annoying in languages where all methods are virtual and overloading is not supported).  Understanding the difference between static and virtual method behaviour is key to OO programming - especially if you are using polymorphism as you are in your example program - suggest reading more on this topic in the Programmers and Language Reference Manuals.

> Can I rely on this mechanism to correctly dispatch method calls in any case, by building a system such as:
> * All values are class instances.
> * They have a unique ancestor class C, on which all possibly overridable methods are declared virtual.
> * On sub-classes, all methods existing on the ancestor(s) are explicitely declared override.
> Then, whatever the class of a variable or of its value for Pascal, the correct method will be called?
> If yes, as I think now, this is a very constructive point :-)

Yes.

> Another one would be to acually know a value's type. How to get its name or, much better, a pointer to it? (Since the language obviously has such a pointer.)

aObj.ClassType will return the TClass of the object.  If you refer to the Manuals as suggested above you will find how to access the TypeInfo for a class.  Note - you can also variably instantiate an object at runtime by working with the TClass...  extending your code example:

type
  TMyCClass = class of C;

function CreateTheCorrectObjectAtRunTime(aC: TMyCClass): C; 
begin
  result := aC.Create;
end;

The result maybe C or any descendent of C (C1, C2, C21, etc) depending on what classtype is passed to the function.  This feature may require that your constructor is virtual so that the compiler can determine the correct constructor to call at runtime (this is why TComponent's constructor is virtual as this behaviour is fundamental to TFiler/TReader and streaming components.  If aC had been the base type TClass this code would work as well - however creating your own class types allows for more robust code and mean you can implement without casting variables - especially useful if your constructor is not virtual, and/or constructor parameters vary between your classes.  If you are interested in this area, Chapter 6 Classes in the Language Reference Manual is worth a read...

Regards

Andrew.


More information about the fpc-pascal mailing list