Eiffel: Analysis, Design and Programming Bertrand Meyer (Nadia Polikarpova) Chair of Software...

103
Eiffel: Analysis, Design and Programming Bertrand Meyer (Nadia Polikarpova) Chair of Software Engineering
  • date post

    22-Dec-2015
  • Category

    Documents

  • view

    232
  • download

    3

Transcript of Eiffel: Analysis, Design and Programming Bertrand Meyer (Nadia Polikarpova) Chair of Software...

Eiffel: Analysis, Design and Programming

Bertrand Meyer

(Nadia Polikarpova)

Chair ofSoftware Engineering

2

- 8 -

Inheritance

3

Overview

Basics

Redefinition

Polymorphism and dynamic binding

Inheritance and contracts

Deferred classes

Polymorphic containers

Inheritance and genericity: constrained genericity

Multiple inheritance

Non-conforming inheritance

Covariance and anchored types

4

Extending the basic notion of class

LIST_OF_CARS

BAG_OF_CARS

LINKED_LIST_OF_CARS

LIST_OF_CITIES

LIST_OF_PERSONS

Abstraction

Specialization

Type parameterization

Type parameterization

Genericity

Inheritance

5

Inheritance basics

Principle:Describe a new class as extension or specialization of an existing class

(or several with multiple inheritance)

If B inherits from A :

As modules: all the services of A are available in B

(possibly with a different implementation)

As types: whenever an instance of A is required, an instance of B will be acceptable

(“is-a” relationship)

6

Terminology

If B inherits from A (by listing A in its inherit clause): B is an heir of A A is a parent of B

For a class A:The descendants of A are A itself and (recursively) the descendants of A ’s heirs Proper descendants exclude A itself

Reverse notions:Ancestor Proper ancestor

More precise notion of instance: Direct instances of A Instances of A : the direct instances of A and its descendants

(Other terminology: subclass, superclass, base class)

B

A

C D

E

7

What you can do to inherited features

Effect (implicit) Redefine Undefine Rename Change export status Select

8

Example hierarchycenter*

perimeter*

perimeter +

...

...

* deferred

+ effective

++ redefined

display*rotate*move*

*FIGURE

*OPEN_FIGURE *

CLOSED_FIGURE

SEGMENT POLYLINE +ELLIPSE

CIRCLE

+POLYGON

TRIANGLE

SQUARE

RECTANGLE

perimeter +

display +

rotate +

move +

perimeter +

+

side1

side2

diagonalperimeter +

+

display +

rotate +

move +

perimeter +

+display ++

rotate ++

move ++

9

Redefinition

Class may redefine (“override”) inherited features

Redefinition is explicit

In line with Uniform Access principle, may redefine inherited function into attribute

Not the other way around!

10

Redefinition 1: polygons

class POLYGON inheritCLOSED_FIGURE

createmake

featurevertex : ARRAY [POINT]vertex_count : INTEGER perimeter : REAL is

-- Perimeter lengthdo from ... until ... loop Result := Result + vertex [i ] . distance (vertex [i +

1]) ... end

endinvariant

vertex_count >= 3vertex_count = vertex.count

end

vertex [i ]

vertex [i + 1]

11

Redefinition 2: rectangles

class RECTANGLE inheritPOLYGONredefine

perimeter end

createmake

featurediagonal, side1, side2 : REAL

perimeter : REAL is-- Perimeter length

do Result := 2 (side1 + side2) endinvariant

vertex_count = 4end

side1

side2diagonal

12

Inheritance, typing and polymorphism

(POLYGON)

(RECTANGLE)

p

r

Assume: p : POLYGON ; r : RECTANGLE ; t : TRIANGLE x : REAL

Permitted:

x := p.perimeterx := r.perimeterx := r.diagonalp := r

NOT permitted:

x := p.diagonal -- Even just after p := r !

r := p

13

Dynamic binding

What is the effect of the following (if some_test is true)?

if some_test thenp := r

elsep := t

end

x := p.perimeter

Redefinition: A class may change an inherited feature, as with POLYGON redefining perimeter.

Polymorphism: p may have different forms at run-time.

Dynamic binding: Effect of p.perimeter depends on run-time form of p.

14

Without dynamic binding?

display (f : FIGURE )do

if “f is a CIRCLE” then ...

elseif “f is a POLYGON” then...

endend

and similarly for all other routines!

Tedious; must be changed whenever there’s a new figure type

15

With inheritance and associated techniques

With:

Initialize:

and:

Then just use:

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 (...)

-- and so on for every-- operation on f !

16

Binding

Binding is the process in which A routine invocation f (a), x.f (a) is connected to

code that is executed Accessing or writing to a variable

aa := Eis connected a memory location.

17

Static vs. dynamic binding

If binding is done at compile time, this is called “Static Binding” using “Static Linking”.

If binding is done at program load time, this is called “Static Binding” using “Dynamic Linking”.

If binding is done at runtime this is called “Dynamic Binding”.

18

Static Binding in C

In the .h header file:

extern int foo (arg c);

extern float my_variable;

In the .c file:

int foo (arg c);

float my_variable;

19

Execution of a call in C

On the caller side: Push the arguments on the stack Push the current PC + 1 on the stack (return

address) Jump to the code to execute

This is “filled out” during linking/binding Clean the stack

20

Execution of a call in C (cont.)

On the callee side: Add some extra memory on the stack for the local

variables Initialize the local variables (if necessary) Execute the implementation of the routine Read the return address from the stack Jump to the return address

21

Dynamic Binding in non-OO

Dynamic binding is not exclusive for object-orientation:

Lisp (1958) Forth (1970) - a mixture called “Threaded Code” C (1970) - Why ?

22

Dynamic Binding in C

#include <stdio.h>void hello () { printf ("Hello\n");}

void world () { printf ("World\n");}

int main (int argc, char **argv) { void (*func)(void);

if (argc > 1) func = hello; else func = world;

func (); /* Dynamic Binding */}

23

Dynamic Binding and OO

We need dynamic binding in object-orientation

Identifiers used in program text are relative to the current object:

Attributes are relative to Current Routines may be redefined in subclasses

24

Using class tables

Class Table Pointer

Integer Field

Integer Field

Integer Field

Class A

Pointer to feature f

Pointer to feature g

1. Read first field from Current

2. Add second field from Current

3. Store result in third field of Current

4. Go to the second entry in Current's

class table

class Afeature

a,b,c : INTEGERf is

doc := a + bg

endg is ...

end

25

With inheritance

Class Table Pointer

Integer Field

Integer Field

Integer Field

Class B

Pointer to feature f

Pointer to feature g

Boolean Field

Pointer to feature h

A

B

class Binherit A redefine ffeature

d: BOOLEANf is ...h is ...

end

26

Contracts and inheritance

Issue: what happens, under inheritance, to

Class invariants?

Routine preconditions and postconditions?

27

Invariants

Invariant Inheritance rule: The invariant of a class automatically includes

the invariant clauses from all its parents, “and”-ed.

Accumulated result visible in flat and interface forms.

28

Contracts and inheritance

rrequire

ensure

rrequire

ensure

a1 : A

a1.r (…)…

Correct call in C:

if a1. then

a1.r (...) -- Here a1. holds end

r ++

C A

D B

client of

inherits from

++ redefinition

29

Assertion redeclaration rule

When redeclaring a routine, we may only:

Keep or weaken the precondition

Keep or strengthen the postcondition

30

A simple language rule does the trick!

Redefined version may have nothing (assertions kept by default), or

require else new_preensure then new_post

Resulting assertions are: original_precondition or new_pre

original_postcondition and new_post

Assertion redeclaration rule in Eiffel

31

The role of deferred classes

Express abstract concepts independently of implementation

Express common elements of various implementations

Terminology: Effective = non-deferred(i.e. fully implemented)

32

In e.g. LIST:

forth

deferred

end

A deferred feature

ensureindex = old index + 1

requirenot after

33

Deferred!

In the same class

search (x : G)-- Move to first position after current

-- where x appears, or after if none.

do from until after or else item = x loop

forth endend

“Programs with holes”

Mixing deferred and effective features

Effective!

34

“Don’t call us, we’ll call you!”

A powerful form of reuse: The reusable element defines a general scheme Specific cases fill in the holes in that scheme

Combine reuse with adaptation

35

Deferred classes in EiffelBase

CONTAINER*

BOX* COLLECTION* TRAVERSABLE*

FINITE* INFINITE*

BOUNDED* UNBOUNDED* COUNTABLE*

RESIZABLE*

BAG* SET* HIERARCHICAL* LINEAR*

TABLE* ACTIVE* INTEGER_ INTERVAL

* BILINEAR*

INDEXABLE*CURSO R_

STRUCTURE

CURSOR_ STRUCTURE

* DISPENSER* SEQUENCE*

ARRAY STRING HASH_TABLE STACK* QUEUE*

… …

* deferred

36

deferred classVAT

inheritTANK

featurein_valve, out_valve: VALVEfill is

-- Fill the vat.require

in_valve.openout_valve.closed

deferredensure

in_valve.closedout_valve.closedis_full

endempty, is_full, is_empty, gauge, maximum, ... [Other features] ...

invariantis_full = (gauge >= 0.97 * maximum)  and  (gauge <= 1.03 *

maximum)end

Deferred classes for analysis

37

Polymorphic data structures

classLIST [G]

feature...last: G is ...extend (x: G) is ...

end

fl: LIST [FIGURE]r: RECTANGLEs: SQUAREt: TRIANGLEp: POLYGON...fl.extend (p); fl.extend (t); fl.extend (s); fl.extend (r)

from fl.start until fl.after loop fl.item.display; fl.forth end

(SQUARE)

(RECTANGLE)

(TRIANGLE)

(POLYGON)

fl

38

Figure hierarchy (reminder)center*

perimeter*

perimeter +

...

...

* deferred

+ effective

++ redefined

display*rotate*move*

*FIGURE

*OPEN_FIGURE *

CLOSED_FIGURE

SEGMENT POLYLINE +ELLIPSE

CIRCLE

+POLYGON

TRIANGLE

SQUARE

RECTANGLE

perimeter +

display +

rotate +

move +

perimeter +

+

side1

side2

diagonalperimeter +

+

display +

rotate +

move +

perimeter +

+display ++

rotate ++

move ++

39

Enforcing a type: the problem

fl.store ("FILE_NAME")

...-- Two years later:

fl := retrieved ("FILE_NAME“)

x := fl.last -- [1]print (x.diagonal ) -- [2]

What’s wrong with this?

If x is declared of type RECTANGLE, [1] is invalid.If x is declared of type FIGURE, [2] is invalid.

40

Object-Test Local

Enforcing a type: the Object Test

if attached {RECTANGLE } fl.last as r then

print (r.diagonal )

… Do anything else with r, guaranteed to be non-void

… and of dynamic type (descendant of) RECTANGLE

elseprint ("Too bad.")

end

Expression to be tested

SCOPE of the Object-Test Local

Optional (if omitted just tests for void)

41

Earlier mechanism: assignment attempt

f : FIGUREr : RECTANGLE...

fl.retrieve ("FILE_NAME")

f := fl.last

r ?= f

if r /= Void then

print (r.diagonal )else

print ("Too bad.")end

42

Assignment attempt

x ?= y

with

x : A

Semantics: If y is attached to an object whose type conforms

to A, perform normal reference assignment.

Otherwise, make x void.

43

What we have seen

Basics

Redefinition

Polymorphism and dynamic binding

Inheritance and contracts

Deferred classes

Polymorphic containers

44

Topics for today

Inheritance and genericity: constrained genericity

Multiple inheritance

Non-conforming inheritance

Covariance and anchored types

45

Inheritance + Genericity

Unconstrained genericity

LIST [G]e.g. LIST [INTEGER], LIST [PERSON]

Constrained genericity

HASH_TABLE [G, H ―> HASHABLE ]

VECTOR [G ―> NUMERIC ]

46

Constrained genericity

class VECTOR [G ] feature plus alias "+" (other : VECTOR [G]): VECTOR [G]

-- Sum of current vector and other.require

lower = other.lower

upper = other.upperlocal

a, b, c: Gdo

... See next ...end

... Other features ...end

47

Adding two vectors

i a b c=+

+ =u v w

1

2

48

Constrained genericity

Body of plus alias "+":

create Result.make (lower, upper)

from i := lower

until i > upper

loopa := item (i )b := other.item (i )c := a + b -- Requires “+” operation on G!

Result.put (c, i )i := i + 1

end

49

The solution

Declare class VECTOR as

class VECTOR [G –> NUMERIC ] feature

... The rest as before ...end

Class NUMERIC (from the Kernel Library) provides features plus alias "+", minus alias "-"and so on.

50

Improving the solution

Make VECTOR itself a descendant of NUMERIC,

effecting the corresponding features:

class VECTOR [G –> NUMERIC ] inheritNUMERIC

feature... Rest as before, including infix "+"...

endThen it is possible to define

v : VECTOR [INTEGER ]vv : VECTOR [VECTOR [INTEGER ]]vvv : VECTOR [VECTOR [VECTOR [INTEGER ]]]

51

In the end...

Genericity is always constrained because

LIST [G]

is just an abbreviation of

LIST [G -> ANY]

52

Combining abstractions

Given the classes

TRAIN_CAR, RESTAURANT

how would you implement a DINER?

53

Examples of multiple inheritance

Combining separate abstractions:

Restaurant, train car Calculator, watch Plane, asset Home, vehicle Tram, bus

54

Composite figures

55

Multiple inheritance: Composite figures

A composite figure

Simple figures

56

Defining the notion of composite figure

COMPOSITE_FIGURE

centerdisplayhiderotatemove…

countputremove…

FIGURELIST

[FIGURE ]

57

In the overall structure

COMPOSITE_FIGURE

FIGURELIST

[FIGURE ]

OPEN_FIGURE

CLOSED_FIGURE

SEGMENT POLYLINE POLYGON ELLIPSE

RECTANGLE

SQUARE

CIRCLE

TRIANGLE

perimeter+

perimeter*

perimeter++

diagonal

perimeter++

perimeter++

perimeter+

58

A composite figure as a list

Cursor

item

forth

afterbefore

59

Composite figures

class COMPOSITE_FIGURE inheritFIGURE

LIST [FIGURE]feature

display-- Display each constituent figure in turn.

dofrom start until after loop

item.display

forth endend... Similarly for move, rotate etc. ...

end

Requires dynamic binding

61

Multiple inheritance: Combining abstractions

COMPARABLE NUMERIC

STRING COMPLEX

INTEGER

REAL

<, <=, >, >=, …

+, –, *, / …(total order

relation)(commutative ring)

62

The Java-C# solution

No multiple inheritance for classes

“Interfaces”: specification only (but no contracts) Similar to completely deferred classes (with no

effective feature)

A class may inherit from: At most one class Any number of interfaces

63

Multiple inheritance: Combining abstractions

COMPARABLE NUMERIC

STRING COMPLEX

INTEGER

REAL

<, <=, >, >=, …

+, –, *, / …(total order

relation)(commutative ring)

64

How do we write COMPARABLE?

deferred class COMPARABLE [G ] feature

end

less alias "<" (x : COMPARABLE [G ]): BOOLEANdeferredend

less_equal alias "<=" (x : COMPARABLE [G ]): BOOLEAN

doResult := Current < x or Current ~ x

endgreater alias ">" (x : COMPARABLE [G ]): BOOLEAN

do Result := x < Current end

greater_equal alias ">=" (x : COMPARABLE [G ]): BOOLEAN

do Result := x <= Current end

65

Lessons from this example

Typical example of program with holes

We need the full spectrum from fully abstract (fully deferred) to fully implemented classes

Multiple inheritance is there to help us combine abstractions

66

Multiple inheritance: Name clashes

f

C

f A B

?

67

Resolving name clashes

f

rename f as A_f

C

f A B

A_f, f

68

Consequences of renaming

a1 : Ab1 : Bc1 : C...

c1.fc1.A_f

a1.fb1.f

rename f as A_f

C

f A B

A_f, f

f

Invalid: a1.A_f b1.A_f

69

Are all name clashes bad?

A name clash must be removed unless it is: Under repeated inheritance (i.e. not a real clash)

Between features of which at most one is effective(i.e. others are deferred)

70

Feature merging

A B C

D

f +f * f *

* Deferred

+ Effective

71

Feature merging: with different names

A B C

D

h +g * f *

* Deferred

+ Effective Renaming

g f h f

classD

inheritA

rename

g as f

end

B

C

rename

h as f

end

feature...

end

72

Feature merging: effective features

A B C

D

f +

f + f +

* Deferred

+ Effective-- Undefine

f --f --

73

Undefinition

deferred classT

inheritS

undefine v end

feature

...

end

74

Merging through undefinition

classD

inheritA

undefine f end

B

C

undefine f end

feature...

end

A B C

D

f +

f + f +

f --f --

* Deferred

+ Effective-- Undefine

75

Merging effective features with different names

A B C

D

h +

f + g +

f --

f --

classD

inheritA

undefine f end

Brename

g as f

undefine f

end

Crename

h as f

end

feature ... end

h f

g f

76

Acceptable name clashes

If inherited features have all the same names, there is no harmful name clash if:

They all have compatible signatures At most one of them is effective

Semantics of such a case: Merge all features into one If there is an effective feature, it imposes its

implementation

78

A special case of multiple inheritance

TEACHER STUDENT

ASSISTANT

UNIVERSITY_MEMBER id

This is a case of repeated inheritance

????

????

79

Indirect and direct repeated inheritance

A

D

B C

A

D

80

Multiple is also repeated inheritance

A typical case:

copy ++

is_equal ++

copy

is_equal

??

copy C_copyis_equal C_is_equal

CLIST

D

ANY

81

Sharing and replication

Features such as f, not renamed along any of the inheritance paths, will be shared.Features such as g, inherited under different names, will be replicated.

A

B C

D

fg

g g_b

g g_c

82

The need for select

A potential ambiguity arises because of polymorphism and dynamic binding:

a1 : ANYd1 : D

a1 := d1

a.copy (…)

copy ++

is_equal ++

copy C_copyis_equal C_is_equal

CLIST

D

copy

is_equal ANY

83

Removing the ambiguity

classD

inheritLIST [T ]

selectcopy, is_equal

end

Crename

copy as C_copy, is_equal as C_is_equal,

...end

84

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.

85

Another application of renaming

Provide locally better adapted terminology.

Example: child (TREE ); subwindow (WINDOW)

91

Non-conforming inheritanceclass ARRAY [G] feature ...

lower, upper: INTEGERresize (l, u: INTEGER)

ensure lower = l; upper = uend

class ARRAYED_LIST [G] inherit

LIST [G]ARRAY [G]

...invariant starts_from_1: lower = 1end

a: ARRAY [INTEGER]; l: ARRAYED_LIST [INTEGER]...a := la.resize (-10, 10)

ARRAYED_LIST

LIST ARRAY

Class invariant violation

92

Inheritance basics: extended

If B inherits from A : As modules: all the services of A are available in B

(possibly with a different implementation)

As types: whenever an instance of A is required, an instance of B will be acceptable

(“is-a” relationship)

If B inherits from A in a non-conforming way: As modules: all the services of A are available in B

(possibly with a different implementation)

No relationship between types!

93

Non-conforming inheritance

class ARRAYED_LIST [G] inherit

LIST [G]inherit {NONE}

ARRAY [G]...invariant starts_from_1: lower = 1end

a: ARRAY [INTEGER]; l: ARRAYED_LIST [INTEGER]...a := la.resize (-10, 10)

ARRAYED_LIST

LIST ARRAY

Non-conforming inheritance

Not allowed

94

No need for select

count

count capacity

ARRAYLIST

ARRAYED_LIST

FINITE

Potential ambiguity is resolved is favor of conforming parent:

f : FINITE [...]al: ARRAYED_LIST [...]

f := al

print (f.count)

Version from LIST

95

Covariance

class LIST [G] feature cursor: CURSOR go_to (c: CURSOR) is do … end

…end

class LINKED_LIST [G] inherit LIST [G] redefine cursor, go_to, ... endfeature cursor: LINKED_CURSOR go_to (c: LINKED_CURSOR) is do … end …end

LINKED_LIST

LIST

LINKED_CURSOR

CURSOR

96

Anchored types

class LIST [G] feature cursor: CURSOR go_to (c: like cursor) is do … end

…end

class LINKED_LIST [G] inherit LIST [G] redefine cursor, ... endfeature cursor: LINKED_CURSOR

-- No need to redefine `go_to’ …

end

97

Semantics of anchored types

In class C :

x: SOME_TYPEy: like x

In class C, y is treated exactly as with y: SOME_TYPE

In a descendant D of C, if x has been redeclared to some other type, y will be treated as it if also had that type.

98

Type redefinition rule

Eiffel: covariant redefinition of result(may change type to a descendant of the original

type) covariant redefinition of arguments

Traditional notion of subtyping : covariant redefinition of result contravariant redefinition of arguments(may change type to an ancestor of the original

type)

Contravariant redefinition: safe but useless

99

The problem with covariance

list: LIST [...]linked_list: LINKED_LIST [...]

c: CURSOR

…list := linked_listlist.go_to (c)

class LIST feature cursor: CURSOR go_to (c: like cursor) is do … end

…end

class LINKED_LIST inherit

LIST

redefine cursor, ... end

feature

cursor: LINKED_CURSOR

-- No need to redefine `go_to’

end

Catcall!

100

CAT calls

CAT stands for Changing Availability or Type

A routine is a CAT if some redefinition changes its export status or the type of any of its arguments

A call is a catcall if some redefinition of the routine would make it invalid because of a change of export status or argument type

101

Catcall cases

Covariant redefinition of arguments

• Non-generic case

• Generic case

Descendant hiding (in earlier versions of Eiffel)

102

Covariant redefinition: non-generic caseclass ANIMAL feature

eat (a_food: FOOD) deferredend

end

class WOLFinherit ANIMAL

redefine eat endfeature

eat (a_meat: MEAT) do … end

end

WOLF

ANIMAL

FOOD

MEAT GRASS

103

animal: ANIMALwolf: WOLFfood: FOODgrass: GRASS

create wolfcreate grassanimal := wolffood := grassanimal.eat (grass)

Covariant redefinition: non-generic case

WOLF

ANIMAL

FOOD

MEAT GRASS

104

animal_list: LINKED_LIST [ANIMAL]sheep_list: LINKED_LIST [SHEEP]sheep: SHEEPwolf: WOLF

sheep_list.extend (sheep)animal_list := sheep_listanimal_list.extend (wolf)

Covariant redefinition: generic case

WOLF

ANIMAL

SHEEP

105

class LINKED_LIST [ANY]feature

extend (v: ANY) do … endend

class LINKED_LIST [SHEEP]feature

extend (v: SHEEP) do … endend

class LINKED_LIST [WOLF]feature

extend (v: WOLF) do … endend

Covariant redefinition: generic case

106

class RECTANGLE inherit POLYGON

export {NONE} add_vertex

end…invariant

vertex_count = 4end

r: RECTANGLE; p: POLYGON...p := rp.add_vertex (...)

Descendant hiding

RECTANGLE

POLYGON

Earlier: catcall!

Now: not allowed

107

class RECTANGLE inherit {NONE} POLYGON

export {NONE} add_vertex

end…invariant

vertex_count = 4end

r: RECTANGLE; p: POLYGON...p := rp.add_vertex (...)

Descendant hiding: solution 1

RECTANGLE

POLYGON

Not allowed

Nonconforming inheritance

108

class POLYGON feature ...variable_vertex_count: BOOLEAN

do Result := True endadd_vertex (...)

require variable_vertex_countdo ... end

end

class RECTANGLE inherit POLYGONredefine variable_vertex_count end

feature ... variable_vertex_count: BOOLEAN = False

end

p: POLYGON...if p.variable_vertex_count then

p.add_vertex (...)end

Descendant hiding: solution 2

RECTANGLE

POLYGON

109

Inheritance: summary (1)

Type mechanism: lets you organize our data abstractions into taxonomies

Module mechanism: lets you build new classes as extensions of existing ones

Polymorphism: flexibility with type safety

Dynamic binding: automatic adaptation of operation to target, for more modular software architectures

Contracts inheritance: ensures properties to clients in presence of polymorphism

Deferred classes: a mechanism to express properties of abstract concepts

110

Inheritance: summary (2)

Polymorphic containers + object test: flexible and type-safe

Constrained genericity: allows calling specific features on expression of parameter types

Multiple inheritance: powerful way of combining abstractions

Non-conforming inheritance: a way to express code reuse without subtyping

Catcalls: result from covariant redefinition of argument types (even more tricky with genericity!)