§2.3.3 Smart lifting

In situations where role and base classes are part of some inheritance hierarchies (extends), choosing the appropriate role class during lifting involves the following rules:

(a) Static adjustment

If a base class B shall be lifted to a role class R that is not bound to (playedBy) B, but if a subclass of R — say R2 — is bound to B, lifting is statically setup to use R2, the most general subclass of R that is bound to B or one of its super-types.

Restriction:
This step is not applicable for parameter mappings of replace callin bindings (§4.5.(d)).

(b) Dynamic selection of a role class

At runtime also the dynamic type of a base object is considered: Lifting always tries to use a role class that is bound to the exact class of the base object. Lifting considers all role–base pairs bound by playedBy such that the role class is a sub-class of the required (statically declared) role type and the base class is a super-class of the dynamic type of the base object.
From those possible pairs the most specific base class is chosen. If multiple role classes are bound to this base class the most specific of these classes is chosen.

(c) Team as closed world

In the above analysis gathering all role-base pairs is performed at compile-time. From this follows, that a team class can only be compiled when all its contained role classes are known and a role class can never be compiled without its team.
The analysis includes all roles and their bindings that are inherited from the super-team.

(d) Selection regardless of abstractness

Smart lifting is not affected by abstractness of role classes. For the effect of abstract role classes see §2.5.

Complex Example:

smart lifting example

role class base class
class R1  
class R2 extends R1 playedBy B2 class B2
class R3 extends R2 /* inherited: playedBy B2 */ class B3 extends B2
class R4 extends R3 playedBy B4 class B4 extends B3
class R5 extends R4 /* inherited: playedBy B4 */  
  class B6 extends B4
class R7 extends R5 playedBy B7 class B7 extends B6
  • If declarations require lifting B3 to R1 this is statically refined to use R2 instead, because this is the most general class declaring a binding to a super–class of B3.
  • If the dynamic base type in the same situation is B6, three steps select the appropriate role:
    1. By searching all playedBy clauses (including those that are inherited) the following role–base pairs are candidates:
      (R2,B2), (R3,B2), (R4,B4) and (R5,B4).
    2. From these pairs the two containing the most specific base class B4 are chosen.
    3. This makes R4 and R5 role candidates, from which the most specific R5 is finally chosen.

If the inheritance hierarchies of the involved base and role classes are given (like in the figure above) the smart lifting algorithm can be rephrased to the following "graphical" rule:

Starting with the dynamic base type (B6 in the example) move upwards the the inheritance relation until you reach a base class bound to a role class indicated by a «playedBy» arrow pointing to the base class (B4). This role class must be conform to the requested role type. Switch to the role side along this arrow (R4). Now move downwards the role inheritance hierarchy as long as the subrole does not refine the playedBy relationship (indicated by another «playedBy» arrow). The bottom role you reach this way (R5) is the role type selected by smart lifting.