Transposition

Revision as of 13:08, 25 October 2006 by Konradm (Talk | contribs) (Transposition, repeated inheritance and replication)

The Language designers view

The new dynamic binding semantics

With the ECMA Eiffel Standard, the dynamic binding semantics of the Eiffel language are almost clearly defined. This new or clarified semantics have some interesting consequences. The following system shows the difference between how the dynamic semantics were (and still are) implemented and how they are specified in the ECMA standard:

SC ABC.jpg
local
   a: A
   b: B
do
   create {C}a
   create {C}b
   a.f          --Line 3 
   b.f1         --Line 4
end

The semantics for line 3 have always been clear, feature f2 should be called. For line 4 the ECMA standard says, that feature f1 is called, whereas the current ISE compiler choses feature f2. So the ECMA standard restrains the power of select, it only has an impact if there are two ore more inheritance paths from the static type to the dynamic type. This is indeed the case for line 3 but not for line 4 of the above example.

The lession learned is:

  • The exact static type of an entity has an important influence on the dynamic binding. A more specific static type may resolve a potential select conflict.

Covariance and the missing part of the ECMA standard

Eiffel allows covariant redefinitions. We reuse the previous example system and add two new classe X and Y:

Example.jpg

Class Y covariantly redefines feature a to the more specific type B. We are interested in the semantics of feature g when executed on an object of class Y. For this we need to know wether the static type of field a is A or B. Of course the static type from the perspective of feature g is still A, f is not even a valid feature name on a target of type B. But the flat-short representation of Y tells us something different(Features of ANY omitted):

class 
   Y
feature
   a: B
   g 
      do
         a.f1
      end
end

So according to the flat-short representation, when g is executed on an object of class Y, the static type of a is B. The flat-short thus implies an other dynamic-binding semantics and this is clearly not a good thing.

Transposition

In the flat-short representation all the inherited features are transposed to the class. It is this transposition that causes the problem. Transposition is also used for the new join semantics (ECMA-3). Furthermore it should be used in the definition of some unfolded forms (for example for the unfolded form of an assertion (8.10.2) or replication). We may say, that if the transposition of a specimen is semanticaly contradicting then this is a huge problem not only but also because the ECMA standard heavily relies on unfolded forms.

Or we state, that the unfolded form of a class has all its inherited features transposed. The unfolded form of class Y would be: (we again ommit the ANY stuff)

class 
   Y
inherit
   X redefine a, b end
feature
   a: B
   g 
      do
         a.f1
      end
end

Apart from the inheritance clause, this unfolded form is similar to the flat-short view of the class. In this unfolded form the inheritance relationship is degraded to a pure subtyping, no feature of X is ever executed for an object of type Y. This is very convenient, for every class we get both its definitive features and its subtype relation. One interesting property of this is, that every unqualified call is statically bound.

Conclusions:

  • With the old dynamic-binding semantics it does not matter wether something is transposed or not.
  • With the new semantics we need to either transpose always or never. Since transposition is indeed needed every inherited feature needs to be transposed.

Incremental transposition

To construct the transposed form of a class, the transposed forms of its direct base classes are needed. To illustrate that we show class Z and its transposition:

class 
   Z
inherit
   Y redefine a end
feature
   a: C
end
class 
   Z
inherit
   Y redefine a,g end
feature
   a: C
   g
      do
         a.f1 
      end
end

Would we have constructed the unfolded form of Z based on X, then feature g would call feature f2.

Transposition, repeated inheritance and replication

We show now, that transposition simplifies the discussion of repeated inheritance and replication. Lets forget for a moment everything we now about replication (ECMA rules 8.16.2, 8.16.3, 8.16.4, 8.16.5), we only need to specify what happens if two transposed features happen to have the same name as in the following two systems S1 and S2:

TransRep.jpg

The unfolded form of class B has two features with name f, since both of them are empty this is ok. The unfolded form of class D also has two features with name f. One of this features calls g1 and the other one calls g2. This is clearly a conflict. Two transposed features should be allowed to have the same name iif they are identical. This is all there is to say about replication. Again, the fact, that we have a definite set of features for every class makes things a simpler.

Transposition

We speak of the transposition of a feature, when we copy an inherited feature to a descendant class and adapt its content according to the inheritance path. When all the inherited features of a class are transposed, we get the flat short form of the class. Transposition is very interesting, since it seems to be the solution to some ambiguities in the language, namely repeated inheritance and replication. In the following system:

class
   B
feature
   f do g end
   g do end
end
class
   D
inherit
   B
      rename f as f1, g as g1 redefine f1 select f1, g1 end
      rename f as f2, g as g2 end
feature
   f1 do ... end
end

class D has the transposed form (we omit the features from ANY):

class
   D
inherit
   B
      rename f as f1, g as g1 redefine f1, g1 select f1, g1 end
      rename f as f2, g as g2 redefine f2, g2 end
feature
   f1 do ... end
   g1 do end   
   f2 do g2 end
   g2 do end   
end

So the transposed form of class D redefines all the features of its parent. Some rather complex rules of the standard become obsolete, when it is just stated, that every inherited feature needs to be transposed (8.16.2, 8.16.3, 8.16.4, 8.16.5). During the transposition there might be conflicts. It is possible that two transposed features have the same name. It remains to be specified how such cases are handled. One solution is to say, that they are valid iif their (transposed) body is equivalent.

Optimization possibilities for transposition

Apart from its power to describe the semantics of the language, transposition is very (maybe too) expensive. It is certainly not acceptable to really transpose every feature from a compiler designer point of view. So we need to find criteria to only transpose when really needed. The following system shows that this is not that easy:

Example.jpg

What happens, when an object of class Y with its field a set to an object of class C has its feature g executed. Only the transposition of g to Y gives the answer:

g
   do
      a.f1
   end

The covariant redefinition of a in Y resolved the potential repeated inheritance conflict. Nevertheless, if g wasn't transposed, feature f2 of class C would have been executed. So the transposition was reallly needed here. We may state:

  • Every feature that uses a target of a covariant type needs to be transposed (Unqualified feature calls don't have a target).

This rule is actualy to restrictive. If our system wouldn't have contained the class C there wouldn't have been any need to transpose f. But such checks would be very expensive.

  • If a feature is not transposition equal ....




Feature g of class X assumes We try to find out, wether it is necessary to really transpose feature g of class Y. The following code snippet gives the answer:

local
   y: Y
   c: C
do
   create y
   create c




Transposition was never necessary in Eiffel compilers but it is now

For the following discussion we use this system of five classes: