2015/4/24Institute of Computer Software Nanjing University Typing, Inheritance and CATCALL 类型,继承以及 CATCALL 问题
2015/4/24Institute of Computer Software Nanjing University 摘要 类型 继承及其它 Deferred Class 单继承与多继承 协变与反变
类型 概念 (值集,操作集) 反映这些值的同质性(意义,目的) 起因 编译技术 作用 Safety Optimization Documentation Abstraction (and Modularity) 2015/4/24Institute of Computer Software Nanjing University
2015/4/24Institute of Computer Software Nanjing University 关于程序设计语言的类型系统 Typing Type checking The process of verifying and enforcing the constraints of types Static vs. Dynamic “Strong” vs. weak Weak typing means that a language will implicitly convert (or cast) types when used. Strong: Safe, Static, strong grantees …
2015/4/24Institute of Computer Software Nanjing University 关于程序设计语言的类型系统 关于范型 Java 枚举类型 Ref : Enum >
2015/4/24Institute of Computer Software Nanjing University Enum 用法 实质
2015/4/24Institute of Computer Software Nanjing University Enum > 回忆: List, List, List 一般的 Foo 回忆: java.lang.class -> java.lang.class
2015/4/24Institute of Computer Software Nanjing University Enum > subClassAwareness public final Class getDeclaringClass()ClassE 返回与此枚举常量的枚举类型相对应的 Class 对象。 public final int compareTo(E o)E 比较此枚举与指定对象的顺序。 public static > T valueOf(Class enumType, String name)EnumClassString 返回带指定名称的指定枚举类型的枚举常量。
2015/4/24Institute of Computer Software Nanjing University 继承与类型 子类型 可替换性: Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T. (Liskov substitution principle) 对于面向对象的计算来说 子类型对象须能接收所有父类型对象能接收的消息
2015/4/24Institute of Computer Software Nanjing University 继承与类型 Are Cows Animals? - By David L. Shang class Animal proc eat (food: AnyFood); end; class Cow is Animal proc eat (food: PlantFood); end;
2015/4/24Institute of Computer Software Nanjing University 继承及其它 何谓继承? 特征(方法、成员函数)重定义 多态与动态绑定 Inheritance and Design by Contract 继承 与 泛型 Assignment attempt
Chair of Software Engineering 何谓继承? Principle: Describe a new class not from scratch but as extension or specialization of one existing class — or several in the case of MULTIPLE inheritance. From the module viewpoint: if B inherits from A, all the services of A are potentially available in B (possibly with a different implementation). From the type viewpoint: inheritance is the ‘‘is- plus-but-except’’ relation. If B inherits from A, whenever an instance of A is required, an instance of B will be acceptable.
Chair of Software Engineering Terminology Parent, Heir Ancestor, Descendant The ancestors of B are B itself and the ancestors of its parents. Proper ancestor, Proper descendant Direct instance, Instance The instances of A are the direct instances of its descendants. (Other terminology: subclass, superclass, base class) A B feature
Chair of Software Engineering Example hierarchy FIGURE * OPEN_ FIGURE * CLOSED_ FIGURE * SEGMENTPOLYLINEPOLYGONELLIPSE CIRCLE RECTANGLETRIANGLE SQUARE extent* barycenter* … display* rotate … perimeter* perimeter+ perimeter++ diagonal... perimeter++ ++ side1 side2 * deferred + effective ++ redefined
2015/4/24Institute of Computer Software Nanjing University 子类对父类的扩展与特化 继承表达的是一种分类演绎的认识方法 “To program is to understand.” 特化:包含范围变小,行为特殊化 扩展:增加新的操作 重定义:改变行为
Chair of Software Engineering Redefinition class POLYGON create make feature vertices: ARRAY [POINT] vertices_count: INTEGER perimeter: REAL is -- Perimeter length do from... until... loop Result := Result + i). distance (i + 1))...end invariant vertices_count >= 3 vertices_count = vertices.count end i (i + 1)
Chair of Software Engineering class RECTANGLE inherit POLYGON redefine perimeter end create make feature diagonal, side1, side2: REAL perimeter: REAL is -- Perimeter length do Result := 2 * (side1 + side2) end invariant vertices_count = 4 end Redefinition (cont’d) side1 side2
Chair of Software Engineering Assume: p: POLYGON; r: RECTANGLE; t: TRIANGLE; x: REAL Permitted: x := p.perimeter x := r.perimeter x := r.diagonal p := r NOT permitted: x := p.diagonal (even just after p := r !) r := p Inheritance, typing and polymorphism (POLYGON) (RECTANGLE) p r 注意理解引 用:运行时 刻实体
Chair of Software Engineering Dynamic binding What is the effect of the following (assuming some_test true)? if some_test then p := r else p := t end x := p.perimeter Redefinition: A class may change an inherited feature, as with RECTANGLE redefining perimeter. Polymorphism: p may have different forms at run-time. Dynamic binding: Effect of p.perimeter depends on run-time form of p.
Chair of Software Engineering The meaning of inheritance The type perspective: Automatic adaptation of operations to the dynamic form of their targets (extendibility): Representation independence. Factoring out reusable operations: Commonality. The module perspective (reusability): Open-closed modules Modularity The Single Choice Principle
Chair of Software Engineering The traditional architecture display (f: FIGURE) is do if ‘‘f is a CIRCLE’’ then... elseif ‘‘f is a POLYGON’’ then... end and similarly for all other routines!
Chair of Software Engineering Applying the Single Choice Principle f: FIGURE c: CIRCLE p: POLYGON... create c.make (...) create p.make (...)... if... then f := c else f := p end... f.move (...) f.rotate (...) f.display (...)...
Chair of Software Engineering The Open-Closed Principle ACE D B FA’ G H I
Chair of Software Engineering The dangers of static binding For every creation procedure cp: {pre cp } do cp {post cp and INV} For every exported routine r: {INV and pre r } do r {INV and post r } The worst possible erroneous run-time situation in object-oriented software development: Producing an object that does not satisfy the invariant of its class. a.f (…) a.g (…) a.f (…) create a.make (…) S1 S2 S3 S4
Chair of Software Engineering The dangers of static binding (cont’d) {INV A } do r A {INV A } {INV B } do r B {INV B } Consider a call of the form a1.r where a1 is polymorphic: No guarantee on the effect of do r A on an instance of B! A B rArA r B ++
Chair of Software Engineering A concrete example w: WINDOW b: BUTTON create b w := b w.display WINDOW BUTTON display display++
Chair of Software Engineering Using original version of redefined feature class BUTTON inherit WINDOW redefine display end feature display is do Precursor display_border display_label end display_label is do... end display_border is do... end
Chair of Software Engineering Use of Precursor Not necessarily the first feature statement. May have arguments. class B inherit A redefine my_feature end feature my_feature (args: SOME_TYPE) is do -- Something here Precursor (args) -- Something else here end A B my_feature my_feature++
Chair of Software Engineering Typing vs. binding What do we know about the feature to be called? Static typing: At least one Dynamic binding: The right one Example: my_aircraft.lower_landing_gear
Chair of Software Engineering Example hierarchy AIRCRAFT * PLANE * COPTER * BOEINGAIRBUS A_320 B_747B_737 B_747_400 * deferred + effected ++ redefined lower_landing_gear* lower_landing_gear++ lower_landing_gear+
2015/4/24Institute of Computer Software Nanjing University 动态绑定 回顾 C++ 和 Java 的绑定机制 C++ 的绑定规则 用户指定 缺省静态 优点?缺点?
Chair of Software Engineering 泛型与继承 LIST_OF_ BOOKS SET_OF_ BOOKS LINKED_LIST _OF_BOOKS LIST_OF_ PEOPLE LIST_OF_ JOURNALS Abstraction Specialization Type parameterization
Chair of Software Engineering Genericity + Inheritance 1: Polymorphic data structures class STACK [G] feature... item: G is... put (x: G) is... end fs: STACK [FIGURE] r: RECTANGLE s: SQUARE t: TRIANGLE p: POLYGON... fs.put (p); fs.put (t); fs.put (s); fs.put (r) fs.item.display (SQUARE) (RECTANGLE) (TRIANGLE) (POLYGON) fs
Chair of Software Engineering Example hierarchy FIGURE * OPEN_ FIGURE * CLOSED_ FIGURE * SEGMENTPOLYLINEPOLYGONELLIPSE CIRCLE RECTANGLETRIANGLE SQUARE extent* barycenter* … display* rotate … perimeter* perimeter+ perimeter++ diagonal... perimeter++ ++ side1 side2 * deferred + effective ++ redefined
Chair of Software Engineering Genericity + Inheritance 2: Constrained genericity class VECTOR [G -> NUMERIC] feature infix "+" (other: VECTOR [G]): VECTOR [G] is -- Sum of current vector and other require lower = other.lower upper = other.upper local a, b, c: G do... See next... end... Other features... end
Chair of Software Engineering Constrained genericity (cont’d) The body of infix "+": create Result.make (lower, upper) from i := lower until i > upper loop a := item (i) b := other.item (i) c := a + b-- Requires a “+” operation on G! Result.put (c, i) i := i + 1 end
Chair of Software Engineering Constrained genericity (cont’d) The body of infix "+": create Result.make (lower, upper) from i := lower until i > upper loop a := item (i) b := other.item (i) c := a + b-- Requires a “+” operation on G! Result.put (c, i) i := i + 1 end
Chair of Software Engineering The solution Declare class VECTOR as class VECTOR [G –> NUMERIC] feature... The rest as before... end Class NUMERIC (from the Kernel Library) provides features infix "+", infix "*" and so on.
Chair of Software Engineering Improving the solution Make VECTOR itself a descendant of NUMERIC, effecting the corresponding features: class VECTOR [G –> NUMERIC] inherit NUMERIC feature... The rest as before, including infix "+"... end Then it is possible to define e.g. v: VECTOR [VECTOR [VECTOR [INTEGER]]]
Chair of Software Engineering Forcing a type: the problem fs.store ("FILE_NAME") Two years later: fs.retrieve ("FILE_NAME") x := fs.item-- [1] print (x.diagonal)-- [2] But: If x is declared of type RECTANGLE, [1] is invalid. If x is declared of type FIGURE, [2] is invalid.
Chair of Software Engineering Assignment attempt f: FIGURE r: RECTANGLE... fs.retrieve ("FILE_NAME") f := fs.item r ?= f if r /= Void then print (r.diagonal) else print ("Too bad.") end
Chair of Software Engineering Assignment attempt (cont’d) x ?= y with x: A If y is attached to an object whose type conforms to A, perform normal reference assignment. Otherwise, make x void.
2015/4/24Institute of Computer Software Nanjing University 延迟类 为什么要延迟类? 从分析到设计到实现的平滑过渡 抽象,复用 Factoring out the commonalities.
Chair of Software Engineering The need for deferred classes In the scheme seen earlier: f: FIGURE; c: CIRCLE; p: POLYGON... create c.make (...); create p.make (...)... if... then f := c else f := p end... f.move (...); f.rotate (...); f.display (...);... How do we ensure that a call such as f.move (...) is valid even though there is no way to implement a general-purpose feature move for class FIGURE?
Chair of Software Engineering Deferred classes deferred class FIGURE feature move (v: VECTOR) is deferred end rotate (a: ANGLE; p: POINT) is deferred end... display, hide,... end Not permitted: create f...
Chair of Software Engineering Example hierarchy FIGURE * OPEN_ FIGURE * CLOSED_ FIGURE * SEGMENTPOLYLINEPOLYGONELLIPSE CIRCLE RECTANGLETRIANGLE SQUARE extent* barycenter* … display* rotate* … perimeter* perimeter+ perimeter++ diagonal... perimeter++
Chair of Software Engineering Deferred classes and features A feature is either deferred or effective. To effect a inherited feature (deferred in the parent) is to make it effective. No need for redefine clause. Like a feature, a class is either deferred or effective. A class is deferred if it has at least one deferred feature (possibly coming from an ancestor) that it does not effect. It is effective otherwise. A deferred class may not be instantiated. BUT: A deferred class may have assertions (in particular, a deferred routine may have a precondition and a postcondition, and the class may have a class invariant).
Chair of Software Engineering Deferred classes Compare with Ada-Modula 2-Java interface/body separation: May contain both deferred and non-deferred elements. More than one implementation is possible. Formal semantic specification (assertions).
Chair of Software Engineering Table variants TABLE * SEQUENTIAL_ TABLE * LINKED_ TABLE + ARRAY_ TABLE + FILE_ TABLE +
Chair of Software Engineering Don’t call us, we’ll call you deferred class SEQUENTIAL_TABLE [G] inherit TABLE [G] feature has (x: G): BOOLEAN is -- Does x appear in table? do from start until after or else equal (item, x) loop forth end Result := not after end
Chair of Software Engineering SEQUENTIAL_TABLE (cont’d) forth is -- Move cursor to the next position. require not after deferred ensure position = old position + 1 end start is -- Move cursor to the first position. deferred ensure empty or else position = 1 end
Chair of Software Engineering SEQUENTIAL_TABLE (end) position: INTEGER is deferred end... empty, found, after,... invariant 0 <= position position <= size + 1 empty implies (after or before) end
Chair of Software Engineering Descendant implementations TABLE * SEQUENTIAL_ TABLE * LINKED_ TABLE + ARRAY_ TABLE + FILE_ TABLE + has+ forth* item* start* forth+ item+ start+ after+ forth+ item+ start+ after+ forth+ item+ start+ after+ after* has*
Chair of Software Engineering Descendant implementations (cont’d) SEQUENTIAL_ TABLE * LINKED_ TABLE + ARRAY_ TABLE + FILE_ TABLE + has+ forth* item* start* forth+ item+ start+ after+ forth+ item+ start+ after+ forth+ item+ start+ after+ after*
Chair of Software Engineering Implementation variants Array Linked list File startforthafteritem (x) c := first_cell rewind i := 1 c := c.right i := i + 1 readend_of_file c := Void f c.item i > countt [i]
Chair of Software Engineering Deferred classes deferred class STACK [G] feature put (x: G) is -- Push x on top of stack. require not full deferred ensure item = x not empty end
Chair of Software Engineering The STACK class (cont’d) remove is -- Pop top element of stack. require not empty deferred ensure not full count = old count – 1 end
Chair of Software Engineering The STACK class (cont’d) full: BOOLEAN is -- Is there no room place for new items? deferred end empty: BOOLEAN is -- Is there no item? deferred end count: BOOLEAN is -- Number of items on stack deferred ensure Result >= 0 end
Chair of Software Engineering The STACK class (cont’d) -- Not all features need be deferred! replace (x: G) is -- Replace top element of stack by x. require not empty do remove put (x) ensure not empty item = x count = old count end invariant not (full and empty) end
Chair of Software Engineering Applications of deferred classes Taxonomy Library organization Capturing common abstractions Capturing common behaviors “Don’t call us, we’ll call you” Analysis High-level architecture and design
Chair of Software Engineering EiffelBase: Container structures CONTAINER * BOX * COLLECTION * TRAVERSABLE * FINITE * INFINITE * BOUNDED * UNBOUNDED * COUNTABLE * RESIZABLE * BAG * SET * HIERARCHICAL * LINEAR * TABLE * ACTIVE * INTEGER_ INTERVAL * BILINEAR * INDEXABLE * CURSOR_ STRUCTURE * DISPENSER * SEQUENCE * ARRAYSTRINGHASH_TABLESTACK * QUEUE * … …
Chair of Software Engineering deferred class VAT inherit TANK feature in_valve, out_valve: VALVE fill is -- Fill the vat. require in_valve.open out_valve.closed deferred ensure in_valve.closed out_valve.closed is_full end empty, is_full, is_empty, gauge, maximum,... [Other features]... invariant is_full = (gauge >= 0.97 * maximum) and (gauge <= 1.03 * maximum) end Object-oriented analysis
2015/4/24Institute of Computer Software Nanjing University 多继承 颇多争议 从描述能力的角度看 从简明性的角度看 问题 名冲突 语法; 语义--来自于重复继承 解决方案?
Chair of Software Engineering Multiple inheritance A class may have two or more parents. What not to use as an elementary example: TEACHING_ASSISTANT inherits from TEACHER and STUDENT. TEACHERSTUDENT TEACHING_ ASSISTANT
Chair of Software Engineering The teaching assistant example This is in fact a case of repeated inheritance: TEACHERSTUDENT TEACHING_ ASSISTANT UNIVERSITY_ MEMBER id ?? ????
Chair of Software Engineering Common examples of multiple inheritance Combining separate abstractions: Restaurant, train car Calculator, watch Plane, asset
Chair of Software Engineering Multiple inheritance: Combining abstractions COMPARABLENUMERIC STRINGCOMPLEX INTEGER REAL DOUBLE **
Chair of Software Engineering Multiple inheritance: Nested windows ‘‘Graphical’’ features: height, width, change_height, change_width, xpos, ypos, move... ‘‘Hierarchical’’ features: superwindow, subwindows, change_subwindow, add_subwindow... class WINDOW inherit RECTANGLE TREE [WINDOW] feature... end
Chair of Software Engineering Multiple inheritance: Composite figures A composite figure Simple figures
Chair of Software Engineering Defining the notion of composite figure FIGURE LIST [FIGURE] COMPOSITE_ FIGURE * display* hide rotate move … count put remove … display +
Chair of Software Engineering Defining the notion of composite figure through multiple inheritance FIGURE LIST [FIGURE] COMPOSITE_ FIGURE * OPEN_ FIGURE CLOSED_ FIGURE SEGMENT POLYLINE POLYGON ELLIPSE RECTANGLE SQUARE CIRCLE TRIANGLE … perimeter+ perimeter* perimeter++ perimeter+ diagonal …
Chair of Software Engineering A composite figure as a list start item forthafter
Chair of Software Engineering Composite figures class COMPOSITE_FIGURE inherit FIGURE redefine display, move, rotate,... end LIST [FIGURE] feature display is -- Display each constituent figure in turn. do from start until after loop item.display forth end end... Similarly for move, rotate etc.... end
Chair of Software Engineering Complex figures Note: a simpler form of procedures display, move etc. can be obtained through the use of iterators.
Chair of Software Engineering Name clashes under multiple inheritance A C foo B
Chair of Software Engineering Resolving name clashes A C foo B rename foo as fogrename foo as zoo
Chair of Software Engineering Resolving name clashes (cont’d) class C inherit A rename foo as fog end B rename foo as zoo end feature...
Chair of Software Engineering Results of renaming a1: A b1: B c1: C... c1.fog c1.zoo a1.foo b1.foo Invalid: a1.fog, a1.zoo, b1.zoo, b1.fog, c1.foo
Chair of Software Engineering Another application of renaming Provide locally better adapted terminology. Example: child (TREE); subwindow (WINDOW).
Chair of Software Engineering The marriage of convenience class ARRAYED_STACK [G] inherit STACK [G] ARRAY [G] feature... end class LINKED_STACK [G] inherit STACK [G] LINKED_LIST [G] feature... end
Chair of Software Engineering Indirect and direct repeated inheritance A B C D A D
Chair of Software Engineering Repeated inheritance Assume class TAXPAYER with attributes age: INTEGER address: STRING bank_account: ACCOUNT tax_id: INTEGER and routines such as pass_birthday is do age := age + 1 end pay_taxes is... deposit_to_account (sum: INTEGER) is... TAXPAYER address tax_id pass_birthday age pay_taxes
Chair of Software Engineering Repeated inheritance (cont’d) Heirs may include SWISS_TAXPAYER and US_TAXPAYER. TAXPAYER address tax_id age pay_taxes pass_birthday US_ TAXPAYER SWISS_ TAXPAYER
Chair of Software Engineering Repeated inheritance (cont’d) The two above classes may in turn have a common heir: SWISS_US_TAXPAYER. TAXPAYER address tax_id pay_taxes pass_birthday US_ TAXPAYER SWISS_ TAXPAYER SWISS_US_ TAXPAYER
Chair of Software Engineering Repeated inheritance issues What happens with features inherited twice from the common ancestor TAXPAYER, such as address, age, tax_id, pass_birthday?
Chair of Software Engineering The inheritance clause inherit SWISS_TAXPAYER rename address as swiss_address, tax_id as swiss_tax_id, pay_taxes as pay_swiss_taxes, bank_account as swiss_bank_account, deposit_to_account as deposit_to_swiss_account,... end US_TAXPAYER rename address as us_address, tax_id as us_tax_id, pay_taxes as pay_us_taxes, bank_account as us_bank_account, deposit_to_account as deposit_to_us_account,... end
Chair of Software Engineering Sharing and replication Features such as age and birthday, not renamed along any of the inheritance paths, will be shared. Features such as tax_id, inherited under different names, will be replicated. TAXPAYER address tax_id pay_taxes pass_birthday US_ TAXPAYER SWISS_ TAXPAYER SWISS_US_ TAXPAYER address us_address tax_id us_tax_id pay_taxes pay_us_taxes address swiss_address tax_id swiss_tax_id pay_taxes pay_swiss_taxes
Chair of Software Engineering The need for select Assume there is a redefinition somewhere along the way: TAXPAYER address US_ TAXPAYER SWISS_ TAXPAYER SWISS_US_ TAXPAYER address++ address us_addressaddress swiss_address
Chair of Software Engineering The need for select (cont’d) A potential ambiguity arises because of 多态与动态绑定 : t: TAXPAYER s: SWISS_TAXPAYER u: US_TAXPAYER su: SWISS_US_TAXPAYER if... then t := s else t := su end... print (t.address)
Chair of Software Engineering Removing the ambiguity class SWISS_US_TAXPAYER inherit SWISS_TAXPAYER rename address as swiss_address, tax_id as swiss_tax_id, pay_taxes as pay_swiss_taxes, bank_account as swiss_bank_account, deposit_to_account as deposit_to_swiss_account,... select swiss_address, swiss_tax_id, pay_swiss_taxes, swiss_bank_account, deposit_to_swiss_account end US_TAXPAYER rename address as us_address, tax_id as us_tax_id,... end
Chair of Software Engineering Creating with a specified type To avoid this: a1: A b1: B... create b1.make (...) a1 := b1 Simply use a1: A... create {B} a1.make (...) A BC
Chair of Software Engineering Once routines If instead of r is do... Instructions... end you write r is once... Instructions... end then Instructions will be executed only for the first call by any client during execution. Subsequent calls return immediately. In the case of a function, subsequent calls return the result computed by the first call.
Chair of Software Engineering Scheme for shared objects class SHARED_OBJECTS feature error_window: WINDOW is once create Result.make (...) end exit_button: BUTTON is once create Result.make (...) end... end class MY_APPLICATION_CLASS inherit SHARED_OBJECTS feature r is do error_window.put (my_error_message) end... end
Chair of Software Engineering Undefining a feature deferred class B inherit A undefine f end feature... end
Chair of Software Engineering Feature merging ABC D f* f+f+
Chair of Software Engineering Feature merging (cont’d) class D inherit A B C feature... end
Chair of Software Engineering Feature merging: with different names ABC D g* f*h+h+ g f h f
Chair of Software Engineering Feature merging: with different names class D inherit A rename g as f end B C rename h as f end feature... end
Chair of Software Engineering Feature merging: effective features a1: Ab1: Bc1: Cd1: D a1.gb1.fc1.hd1.f ABC D g*g* f*f*h+h+ g f h f f-f-f-f-
Chair of Software Engineering Feature merging: effective features class D inherit A rename g as f undefine f end B C rename h as f undefine f end feature... end
Chair of Software Engineering When is a name clash acceptable? (Between n features of a class, all with the same name, immediate or inherited.) They must all have compatible signatures. If more than one is effective, they must all come from a common ancestor feature under repeated inheritance.
Chair of Software Engineering Feature adaptation clauses rename export undefine redefine select
Chair of Software Engineering Export adaptation class B inherit A export {ANY} all {NONE} h {A, B, C, D} i, j, k end feature...
2015/4/24Institute of Computer Software Nanjing University 多继承的替代方案 Java Interface 重复继承 Interface 没关系 名冲突仍是问题 损失实现的继承式复用 可通过聚合包含部分弥补
2015/4/24Institute of Computer Software Nanjing University 更正 public class ClassCastException extends RuntimeException RuntimeException
2015/4/24Institute of Computer Software Nanjing University 小结 继承是 “ 面向对象程序设计 ” 核心机制之一 从实现机制角度的理解(静态组成,动态绑定) 从类型与模块相统一的角度理解 从 Design by Contract 的角度理解 抽象类(延迟类) 多继承问题
2015/4/24Institute of Computer Software Nanjing University 继承与类型 “ 类型 ” 回顾 概念? Value set, Operation set 作用? Safety, Documentation, Optimization, Abstraction 类和类型的关系 Ref:
2015/4/24Institute of Computer Software Nanjing University Are Cows Animals? animal: Animal; animal.eat (meat); Being an Animal, a cow must eat any food Know the type of the animal before let it eat A cow is not an animal A cow can eat something more than food Let a cow have two eat methods
2015/4/24Institute of Computer Software Nanjing University Are Cows Animals? Given an animal, it cannot eat any food class Animal proc eat (food: thisAnimal's FoodType); end; the food type of a herbivore is the food type of a herbivore the food type of a carnivore is the food type of a carnivore
2015/4/24Institute of Computer Software Nanjing University Are Cows Animals? When the type of an argument depends on the type of the enclosing object, describe the dependency in the superclass; so that the subclass can be covariantly specified without narrowing, a violation of the superclass's interface specification;
2015/4/24Institute of Computer Software Nanjing University Are Cows Animals? When one input type depends on the other input type in a polymorphic function/method interface, describe the dependency in the interface; so that the function implementation can be type-checked statically and locally.
2015/4/24Institute of Computer Software Nanjing University Are Cows Animals? When the type of an argument is independent to the type of the enclosing object, stick to invariance. If an individual subclass need to specialize the type, it is exception becuase the type of the argument is independent in general. You can use run-time type check or multiple disptach to deal with this exceptional case. We can live without contravariance.
2015/4/24Institute of Computer Software Nanjing University Detail Discussion Let’s turn to Bertrand Meyer’s slides :
Chair of Software Engineering Object-Oriented Software Construction Bertrand Meyer Lesson 21 Last update: 25 May 2004 Type issues, covariance and catcalls
Chair of Software Engineering What’s special about this lecture Mix of: Fundamental concepts Unsolved issues Recent proposal
Chair of Software Engineering Flexibility vs. safety Expressive power (no “ bondage and discipline ” language) Protection against crashes and attacks
Chair of Software Engineering Typing approaches Pascal x := y Only if types of x and y are identical! Smalltalk x.f always permitted, not static type check! At execution time: “ Message not understood ”
Chair of Software Engineering Like Pascal in basic forms But polymorphism allows more flexible assignment rule: x := y permitted if type of y “ conforms to ” type of x Typed O-O languages
Chair of Software Engineering Basic type rules in typed O-O languages Eiffel, Java,.NET... In every assignment x := y (or argument passing), type of y conforms to type of x. In every feature call x.f(…) (qualified), f is an exported feature of the class of x. C++: “ A little bit typed ” (Casts)
Chair of Software Engineering Terminology Typed vs untyped languages More accurate: Statically typed, vs Dynamically typed
Chair of Software Engineering Typing is always pessimistic Invalid in Pascal: var n: INTEGER n := 0.0 if 0 > 1 then begin n := 0.0 end
Chair of Software Engineering The basic goal A programming language is statically typed if its definition includes a set of type rules, guaranteeing that no execution of a valid program will ever produce a run-time type failure. A type rule is a validity constraint involving the types associated with program elements. A validity constraint for a programming language is a boolean condition applicable to any syntactically legal program text in the language.
Chair of Software Engineering Precise definitions An object-oriented program is class-level-valid if it satisfies the following properties: In every assignment x := y (or argument passing), type of y conforms to type of x. In every feature call x.f(…) (qualified), f is an exported feature of the class of x. Without catcalls, any class-level-valid program would be type-safe!
Chair of Software Engineering The issue: flexibility vs safety Find a type system that: Supports covariance and genericity Permits full static type checking Stated differently: Disprove the “ Pierre America conjecture ” that one can have at most two of polymorphic substitution, covariance, and static type checking Fix the “ holes ” in Eiffel ’ s type system
Chair of Software Engineering A typical covariance situation
Chair of Software Engineering Original class class BOAT feature captain: SKIPPER -- Skipper assigned to this boat sail (c: SKIPPER) is -- Appoint c as captain of this boat. require c /= Void do captain := c ensure captain = c end
Chair of Software Engineering Original class (simplified) class BOAT feature captain: SKIPPER sail (c: SKIPPER) is do captain := c end ARRAYED_ BOAT STACK CAT captain sail(...) sail(...) ARRAYED_ SKIPPER STACK CAT_ SKIPPER captain
Chair of Software Engineering Heir class class CAT inherit BOAT redefine captain, sail end feature captain: CAT_SKIPPER sail (c: CAT_SKIPPER) is do captain := c end
Chair of Software Engineering Original class, using anchored type class BOAT feature captain: SKIPPER sail (c: like captain) is do captain := c end No explicit redefinition necessary for sail in CAT (see next)
Chair of Software Engineering Heir class class CAT inherit BOAT redefine captain end feature captain: CAT_SKIPPER end
Chair of Software Engineering Static typing vs. dynamic binding x.f Static typing: ensures that there is AT LEAST ONE FEATURE Dynamic binding: ensures that it is THE RIGHT FEATURE
Chair of Software Engineering Catcalls boat1: BOAT; cat1: CAT skipper1: SKIPPER; cat_skipper1: CAT_SKIPPER... boat1 := cat1... boat1.sail (skipper1) The captain of this catamaran is now a plain SKIPPER ! Might try to do captain.repair_second_hull (see next) captain (SKIPPER) (CAT) “Ticking bomb”
Chair of Software Engineering Catcalls class BOAT feature do_maintenance is do -- Something here. end feature do_maintenance is do captain.repair_second_hull end class CAT inherit BOAT redefine do_maintenance end
Chair of Software Engineering Catcall situation ARRAYED_ BOAT STACK CAT captain sail(...) sail(...) repair_second_hull ARRAYED_ SKIPPER STACK CAT_ SKIPPER captain
Chair of Software Engineering Consequences of a catcall Crash? Security attack?
Chair of Software Engineering Catcalls: source #2 — Genericity skipper_list: LIST [SKIPPER] cat_skipper_list: LIST [CAT_SKIPPER]... skipper_list := cat_skipper_list skipper_list.extend (skipper1) cat_skipper1 := cat_skipper_list.last
Chair of Software Engineering Catcalls: source #3 — Descendant hiding class RECTANGLE inherit POLYGON export {NONE} add_vertex end... end poly1 := rect1... poly1.add_vertex (...)
Chair of Software Engineering CAT Changed Availability or Type
Chair of Software Engineering Pierre America, 1990 At most two of: Polymorphic substitution Covariance Static type checking
Chair of Software Engineering Previous solutions: novariance C++, Java,.NET... Eliminates the problem (obviously) Forces programmers to do the conversions themselves May result in brittle code
Chair of Software Engineering Previous solutions: contravariance Results specialized, arguments generalized Solves the problem Only problem: doesn ’ t match practical needs The world seems to be covariant.
Chair of Software Engineering Previous solutions: catch catcalls Generate code to check arguments Cause exception if wrong type Avoids the security issue Disadvantages: Performance penalty in all cases Forces issue on client! No easy way to force client to handle exception Exception too drastic
Chair of Software Engineering Previous solutions: Overloading Consider that redefinition creates a new variant of the routine but doesn ’ t obliterate the previous one. Name resolution combines dynamic binding and overloading. Semantic rules can be devised (Giuseppe Castagna, ENS Paris) Doesn ’ t seem compatible with goals of O-O programming
Chair of Software Engineering Previous solutions: system-level validity Considering all assignments, compute dynamic type set (DTS) of any variable x. If there is an assignment x := y, or a corresponding argument passing, all elements of DTS of y are also in the DTS of x. No attempt at control flow analysis Fixpoint algorithm Helps with optimization Disadvantages: Pessimistic Not incremental Difficulty of giving precise diagnostics
Chair of Software Engineering Previous solutions: class-level validity If there is an assignment x := y and y is of a different type from x, or (recursively) y is polymorphic, consider x polymorphic. Any formal routine argument is polymorphic Disallow x. r (...) if x is polymorphic and r is a CAT routine. Local information, all incremental Disadvantages: Pessimistic Difficulty of giving precise diagnostics
Chair of Software Engineering Recent Eiffel developments Tuples Expanded inheritance
Chair of Software Engineering Tuple types and tuples TUPLE [X, Y, Z] Denotes sequences of at least three elements, first of type X, second of type Y, third of type Z Individual tuple: [x1, y1, z1] Conformance relations TUPLE [X, Y, Z] TUPLE [X, Y]
Chair of Software Engineering Expanded inheritance class C inherit A expanded B feature... end No polymorphism permitted: a1 := c1 -- OK b1 := c1 -- Not permitted
Chair of Software Engineering The new solution (1) Covariance etc. OK with expanded inheritance Covariance also OK with non-exported features x.f(a) -- Qualified f(a) -- Unqualified
Chair of Software Engineering The new solution (2) Allow covariant redefinition even with polymorphism! Replacement ( “ recast ” ) must be provided Also applies to generic case
Chair of Software Engineering Covariant cats class CAT inherit BOAT redefine captain, sail end feature captain: CAT_SKIPPER sail (c: CAT_SKIPPER) is recast trained_as_cat_skipper do captain := c end
Chair of Software Engineering A recast function trained_as_cat_skipper (s: SKIPPER): CAT_SKIPPER is -- Version of skipper s reborn as cat skipper require exists: s /= Void do create Result.train_skipper (s) end
Chair of Software Engineering In CAT_SKIPPER class CAT_SKIPPER inherit SKIPPER create make_from_skipper feature -- Initialization train_skipper (s: SKIPPER) is require s /= Void s.trained_as_cat_skipper do … end
Chair of Software Engineering The latest… No more recast function Use exceptions instead sail (c: CAT_SKIPPER) is do captain := c rescue … Can use c … end
Chair of Software Engineering The multi-argument case r (x: TYPE1 ; y: TYPE2; z: TYPE3) is recast transform do... end with transform (x: OLD1 ; y: OLD2; z: OLD3): TUPLE [TYPE1, TYPE2, TYPE3] is do... end
Chair of Software Engineering The generic case In C [G], if there is a routine r (x: G) it must have a recast clause!
Chair of Software Engineering Possible criticism Creates a copy What if LIST of catamarans
Chair of Software Engineering The descendant hiding case Expanded inheritance works, of course More flexibility: still under discussion
Chair of Software Engineering More work Implement Analyze benefits and disadvantages further Study real software Formalize through a mathematical model, prove Solve descendant hiding issue
Chair of Software Engineering Some tentative conclusions Flexibility can be reconciled with safety No need to choose between anarchy and “ bondage and discipline ” Static typing is practical Language design is needed Language design is fun Committees work! Don ’ t sail a catamaran unless you know how to
2015/4/24Institute of Computer Software Nanjing University Summary Inheritance Concept: Viewpoint of type and modular Usage: Interface vs. Implementation inheritance Advanced topic Covariance vs. Contra-variance CATCALL problem Polymorphic substitution Covariance Static type checking