Difference between revisions of "Dynamic Binding"
m (→Dynamic binding in finalized code) |
m (→Dynamic binding in workbench code) |
||
Line 86: | Line 86: | ||
The dynamic binding is done in two steps | The dynamic binding is done in two steps | ||
+ | {|border="0" cellpadding="2" cellspacing="0" align="center" | ||
+ | |-valign="top" -halign="center" | ||
+ | | | ||
+ | <code>[c, N] | ||
(FUNCTION_CAST(void, (EIF_REFERENCE)) RTVF(496, 35, "f", arg1))(arg1); | (FUNCTION_CAST(void, (EIF_REFERENCE)) RTVF(496, 35, "f", arg1))(arg1); | ||
+ | </code> | ||
+ | | | ||
+ | |} | ||
+ | |||
Dynamic binding in workbench mode is optimized for flexibility and not for speed (See [[Melting Ice Technology]]. | Dynamic binding in workbench mode is optimized for flexibility and not for speed (See [[Melting Ice Technology]]. |
Revision as of 00:29, 15 January 2007
Warning: Warning: Article under development
Contents
Introduction
Dynamic binding is a key feature behind object technology. In the following piece of code:
foo (a: A) do a.f end |
It is not known at compile time, which feature has to be called for call a.f. This depends on the exact type of the object referenced by a, also called its dynamic type.
Some Ids
In the following sections several ids are introduced. Their explanation is based on the following example system (Further referenced as the ABC system):
routine_id
In a compiled Eiffel system, every feature that is a seed gets its own unique routine_id. Features that are just inherited or are a redeclaration have the same routine_id as their precursor (See Routine IDs).
It is possible for a feature to have more than one routine_id when it has more than one precursor. This is the case for feature j of class C that redefines both feature g of A and feature h of B and thus gets both their routine_id's.
As it will be shown later, the chosen routine_id have an impact on the dynamic binding semantics. In class C the feature f_b gets the routine_id 1 since it is selected, the not selected feature f of C gets a new routine_id.
body_id and real_body_id
Every routine body, that means every declaration or redeclaration, gets its own unique body_id. The body_id of feature g in classes A and B are the same since g is not redefined in B.
A body of a generic class may need several translated versions, when there are different type instantiations of the class. For getting the right version of the correct type instantiation the real_body_id is used. There might be for example two translations for feature f of class A. One for each of the types A [INTEGER] and A [STRING]. Their real_body_id will thus be different. The real_body_id is mostly important in workbench mode.
feature_id
Every feature of a class gets a feature_id that is unique in the context of this class.
class_id and type_id
Every class gets a unique class_id an every type a unique type_id.
Dynamic binding in finalized code
In finalized code the dynamic binding is very simple. For every routine_id there exists an array, that maps dynamic type ids to function pointers. This array is called routine table.
For attributes there is also a routine table but it contains offsets instead of function pointers.
The code snipped shows how the routine table for routine_id 1 looks like and on the right side a dynamically bound call (its the feature foo from above):
char *(*Txiockf[6])(); void Txiockf_init () { Txiockf[0] = (char *(*)()) A_INTEGER_f; Txiockf[1] = (char *(*)()) A_REFERENCE_f; Txiockf[2] = (char *(*)()) B_INTEGER_f_g; Txiockf[3] = (char *(*)()) B_REFERENCE_f_g; Txiockf[4] = (char *(*)()) B_INTEGER_f_g; Txiockf[5] = (char *(*)()) B_REFERENCE_f_g; } |
void Fcubdx0 (EIF_REFERENCE Current, EIF_REFERENCE arg1) { ... //Offset 50 is used to allow a smaller routine table (FUNCTION_CAST(void, (EIF_REFERENCE)) Txiockf[Dtype(arg1)-50])(arg1); ... } |
The function names in the routine table are artificial to ease its understanding. A_INTEGER_f for example is the function for the feature f of type A [INTEGER].
Two facts become obvious:
- The type_id of inherited classes should be close together, otherwise the routine tables will have big holes and become huge.
- When in the above example an object of a wrong type is passed to Current it will have disastrous consequences.
Dynamic binding in workbench code
The dynamic binding is done in two steps
(FUNCTION_CAST(void, (EIF_REFERENCE)) RTVF(496, 35, "f", arg1))(arg1); |
Dynamic binding in workbench mode is optimized for flexibility and not for speed (See Melting Ice Technology.