The world is covariant: is it safe? Bertrand Meyer & Emmanuel Stapf Chair of Softw are Engineering
Collaborations & acknowledgements Emmanuel Stapf (Eiffel Software, California) Martin Seiler, Julian Tschannen (Eiffel Software + ETH) Alexander Kogtenkov (Eiffel Software, Moscow) Yi Wei (ETH) for some of the statistics ECMA TG4 committee, especially Mark Howard (AXA Rosenberg, California) Eric Bezault (AXA Rosenberg) Bernd Schoeller (ETH) and all the people who have criticized Eiffel’s design over the years 2
The need for covariance Client CUSTOMER BEVERAGE Inherit drink : BEVERAGE serve ( b : BEVERAGE ) do drink := b ensure SOFT_ ALCOHOL drink = b DRINK end MINOR drink : SOFT_DRINK serve ( b : SOFT_DRINK ) do drink := b end 3
Defeating covariance (1) Client Client CUSTOMER BEVERAGE Inherit Inherit drink : BEVERAGE serve ( b : BEVERAGE ) do drink := b end SOFT_ MINOR ALCOHOL DRINK b : BEVERAGE drink : SOFT_DRINK serve ( b : SOFT_DRINK ) b := Vodka do drink := b end c := Shiloh c := Shiloh c . serve ( Vodka ) Vodka : ALCOHOL c . serve ( Vodka ) c : CUSTOMER c . serve ( b ) Shiloh : MINOR 4
Defeating covariance (2) CUSTOMER BEVERAGE drink : BEVERAGE serve ( b : BEVERAGE ) do drink := b end SOFT_ MINOR ALCOHOL DRINK drink : SOFT_DRINK bus : LIST [ CUSTOMER ] serve ( b : SOFT_DRINK ) school_bus : LIST [ MINOR ] do drink := b end bus := school_bus Generic Vodka : ALCOHOL conformance bus . item . serve ( Vodka ) c : CUSTOMER Shiloh : MINOR 5
Terminology Catcall: incorrect application of a feature to an object as a result of � Incorrect argument type � Information hiding violation (CAT: Changed Availability or Type) fly BIRD ?? OSTRICH 6
Mitigating mechanism 1: non-conforming inheritance class B C inherit { NONE } B feature ... C end No polymorphism permitted: b1 : B b1 := c1 -- Invalid c1 : C 7
Mitigating mechanism 2: anchored types In practice: anchored types class CUSTOMER feature drink : BEVERAGE serve ( b : BEVERAGE ) class CUSTOMER feature do drink := b drink : BEVERAGE end serve ( ) b : like drink end do drink := b class MINOR inherit end end CUSTOMER redefine drink, serve end feature class MINOR inherit drink : SOFT_DRINK CUSTOMER redefine drink end serve ( b : SOFT_DRINK ) feature do drink : SOFT_DRINK drink := b end end end 8
Anchoring to Current Also possible, in a class C : x : like Current In any descendant D of C (including C itself), x has type D 9
Mitigating mechanism 3: flat type checking An assignment T B x := y r x : T may be valid in a routine r of do y : T x := y a class B but not necessarily e nd in a descendant C which only redefines x (covariantly) The Eiffel type system now specifies that every class x : U must be independently valid U C “Flat type checking” 10
A typical example (EiffelBase library) (TWO_WAY_LIST) (LINKED_LIST) (LINKABLE) (BI_LINKABLE) class LINKABLE [ G ] feature class BI_LINKABLE [ G ] inherit item : G LINKABLE [ G ] right : LINKABLE [ G ] redefine right end put_right ( x : like right ) feature right : BI_LINKABLE [ G ] do right := x end end left : like right put_left ( x : like right ) do left := x end end 11
The practical picture Measures courtesy of Yi Wei (ETH) Product Lines Features * Covariant Covariant argument result (thousands) (thousands) EiffelBase 65 5.5 1.1% 1.3% EiffelStudio + 660….. 51 0.7% 1.2% Libraries Client code 1300….. 38 0.9% 3.1% All 1900….. 89 0.7% 2.0% EiffelVision 99 6.7 0.7% 3.9% common API Financial 1600 122 1% 1.4% system *New and redeclared features only. Rounded. + Windows version 12
Explicit vs implicit covariance Product Features with Explicit like Current like x covariant args covariance EiffelBase 59 39% 8% 52% EiffelStudio 697 53% 8% 39% Financial system 1173 59% 2% 39% 13
Type intervals CUSTOMER Vodka : ALCOHOL Shiloh : MINOR drink : BEVERAGE serve ( b : BEVERAGE ) c : CUSTOMER .. MINOR do drink := b end c := Shiloh MINOR c . serve ( Vodka ) drink : SOFT_DRINK serve ( b : SOFT_DRINK ) -- Now invalid do drink := b end 14
Type intervals c : CUSTOMER .. MINOR x : CUSTOMER .. CUSTOMER x := Shiloh c := Shiloh -- Now invalid x . serve ( Vodka ) c . serve ( Vodka ) -- Now invalid Rule: a call x . f ( a ), Abbreviations: with x : T .. U , must means x : T .. NONE x : T be valid when x is means LIST [ T .. T ] LIST [ T ] given any type in T .. U 15
A simplified version c : CUSTOMER x: frozen CUSTOMER c := Shiloh x := Shiloh Invalid OK x . serve ( Vodka ) c . serve ( Vodka ) OK Invalid Rule: a call x . f ( a ), with x: T not frozen, must be valid when x is given any descendant type of T 16
Genericity rule bus : LIST [ CUSTOMER ] vbus : LIST [ variant CUSTOMER ] school_bus : LIST [ MINOR ] vbus := school_bus bus := school_bus OK Invalid vbus . extend ( Shiloh ) bus . extend ( Shiloh ) OK Invalid Rule: � An assignment with a different actual generic parameter requires the “variant” mark. � The variant mark precludes the use of a routine with an argument of a formal generic parameter type 17
Anchored (“ like ”) declarations New results: � “Flat type checking” guarantees that like Current declarations are safe b : like a � b : like a , with a of type T , may be considered an abbreviation not for b : T as now, but for b : frozen T Then only explicit (non-anchored) covariance remains! 18
Note The mechanism permits export restrictions in descendants, if desired. fly BIRD ?? OSTRICH 19
Partial function Proof framework “Direct semantics” of Eiffel: the language is (re)-defined as a mathematical theory Routines are functions with the following signatures (George Bush principle): � Object → Value* → State → Value (query) | | � Object → Value* → State → State (command) | | Each class is associated with two sets of objects: � Direct instances � Instances (includes direct instances of descendants) A polymorphic variable may denote any instance, a non- polymorphic one only a direct instance Prove that with the rules given all applications of partial functions are within the corresponding domain 20
Recommend
More recommend