eiffel: analysis, design and programming bertrand meyer (nadia polikarpova) chair of software...
Post on 22-Dec-2015
232 views
TRANSCRIPT
Eiffel: Analysis, Design and Programming
Bertrand Meyer
(Nadia Polikarpova)
Chair ofSoftware Engineering
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)
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
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]
53
Examples of multiple inheritance
Combining separate abstractions:
Restaurant, train car Calculator, watch Plane, asset Home, vehicle Tram, bus
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+
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
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)
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 --
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
????
????
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!)