[fpc-devel] Using case statement instead of VTable

Marco van de Voort fpc at pascalprogramming.org
Tue Apr 11 11:02:52 CEST 2023

On 11-4-2023 10:41, Hairy Pixels via fpc-devel wrote:
>>>   case animal.type of
>>>     TDog: TDog(animal).DoSomething;
>>>     TCat: TCat(animal).DoSomething;
>>>     TMouse: TMouse(animal).DoSomething;
>>>   end;
>> This doesn't happen. There is no class that is TDog,Cat and mouse. Usually a VMT governs the relation between parent and child, i.e.   TDog and TAnimal.  The TDog nor the TAnimal implementation has no knowledge of the other mammals.
> Address this part first since maybe my example was poor. I was trying to model how polymorphism is done in pure procedural code. I used to write code like this so I kind of remember.
> The idea is that there is a record with an enum which is the type of the object. Then anytime you have a polymorphic function (an override) you dispatch on it using a case.

That's what I thought, yes. But the whole analysis stays the same:

- you don't have a list of all possible polymorphic types in the 
application when you compile the average dispatch point, that is in the 
realm of whole-program optimization.   (I saw your later mail that you 
understood this, but I already composed this message when it arrived)

- The code is still more bulky. To get the type from the instance 
pointer is as expensive as the getting the vmt, and while the dispatch 
via the VMT is a single instruction on x86 (call *[vmt+offset]), you 
still have to spend a comparison and a branch per case (dog/cat/mouse) 
extra, with as only saving grace that the indirection of the call 
instruction disappears. Both bulkier and slower.

Another issue that I just thought about:

- you now only consider one virtual method per class. But think of more 
complex class hierarchies where various methods are introduced at 
various levels. Every virtual method then gets its own set of possible 
classes, and thus enum. This reduces to one entry per virtual method, 
just like in the VMT, only difference is that it is an enum instead of a 
pointer. (but the VMT pointer table is duplicated in the case statements 
of every dispatch call)

To judge new language schemes, always factor in multi unit examples, and 
ask yourself what you know at each point of the compilation. (e.g. 
typically you only know the interface of an USES'd unit, and not its 
implementation, and not other units). Similarly, the simple case is only 
a step up to also evaluate more elaborate cases. The devil is always in 
the details.

More information about the fpc-devel mailing list