Lecture 18 - cs.Virginia

Lecture 18: Behavioral
Subtyping and Eiffel
Must it be assumed that because
we are engineers beauty is not
our concern, and that while we
make our constructions robust
and durable we do not also strive
to make them elegant?
Is it not true that the genuine
conditions of strength always
comply with the secret conditions
of harmony?
Gustav Eiffel
CS655: Programming Languages
David Evans
University of Virginia
http://www.cs.virginia.edu/~evans
Computer Science
Menu
• Behavioral Subtyping Recap and
Example
• Eiffel’s Type System
• Method overriding in C++
29 March 2001
CS 655: Lecture 18
2
Subtype Definition (S  T)
1. Subtype methods preserve the
supertype methods’ behavior:
•
•
Signatures have contravariant arguments,
covariant results
Pre-conditions of T imply preconditions of
S; post-conditions of S imply postconditions of T.
2. Subtypes preserve supertype properties
•
•
Invariant of S implies invariant of T.
Constraint of S implies constraint of T.
29 March 2001
CS 655: Lecture 18
3
Subtype Relation 2: Preserves
supertype Properties
2. Subtypes preserve supertype
properties
For all states p and q such that p
precedes q, for all x: S:
Invariant Rule
IS  IT [ A (xp) / xp]
Constraint Rule
CS  CT [A (xp) / xp, A (xq) / xq ]
“covariance – subtype is stronger”
29 March 2001
CS 655: Lecture 18
4
Example
• Liskov & Wing showed stack  bag
• Is bset  bag?
– bset specification on the Manifest
– bag in Liskov & Wing, Figure 1
29 March 2001
CS 655: Lecture 18
5
bset = type
uses BSet (set for S)
for all s: bset
invariant max(sp.elements) <= sp.limit,
min (sp.elements) >= 0.
constraint sp.limit = sq.limit
insert = proc (i: int)
requires i <= sp.limit  i >= 0.
modifies s
ensures spost.limit = spre.limit
 spost.elements = spre.elements  {i}
29 March 2001
CS 655: Lecture 18
6
contains = proc (el: int) returns (bool)
ensures result = el  s
choose = proc () returns (int)
requires spre.elements  {}
modifies s
ensures
spost.elements = spre.elements – { result }
 result  spre.elements
 spost.limit = spre.limit
size = proc () returns (int)
ensures result = | s.elements |
equal = proc (t: set) returns (bool)
ensures result = (s = t)
29 March 2001
CS 655: Lecture 18
7
Subtype Definition (S  T)
1. Subtype methods preserve the
supertype methods’ behavior:
•
•
Signatures have contravariant arguments,
covariant results
Pre-conditions of T imply preconditions of
S; post-conditions of S imply postconditions of T.
2. Subtypes preserve supertype properties
•
•
Invariant of S implies invariant of T.
Constraint of S implies constraint of T.
29 March 2001
CS 655: Lecture 18
8
Subtype Condition 1: Methods Rule
• Methods rule:
– Pre-condition “contravariance – subtype is weaker”

x:s
mT.pre [ A (xpre) / xpre ]  mS.pre
Replace every xpre in mT.pre with A (xpre).
Abstraction function, A : s  t.
– Post-condition “covariance – subtype is stronger”
mS.post  mT.post [A (xpre) / xpre, A (xpost) / xpost]
29 March 2001
CS 655: Lecture 18
9
We need an Abstraction Function
A type is: < set of objects, set of values, set of methods >
bset = <Oset, BSet, { insert, contains, choose, size, equal } >
bag = <Obag, BBag, { put, get, card, equal } >
• We need an abstraction function that maps both to
the same abstract type:
A : BSet  BBag
BSet: < s.elems, s.limit >
BBag: < s.elems, s.bound >
s : BSet A (s) = < s.elems, s.limit >
• Renaming: R(insert) = put, R(choose) = get,
R(size) = card, R(equal) = equal
29 March 2001
CS 655: Lecture 18
10
Check method choose  get
1. Preserves method behavior.
• Signatures:
get = proc () returns (int); choose = proc () returns (int)
• Pre-condition of get  pre-condition of choose
x : BSet get.pre [ A(xpre) / xpre ]  choose.pre
bpre.elems  {} [A(bpre) / bpre ]  spre.elems  {}
 s : BSet; A (s) = < s.elements, s.limit > so we can replace
bpre.elems with spre.elems and the implication holds.
• Post-condition of choose  post-condition of get
– Can prove with similar renaming
29 March 2001
CS 655: Lecture 18
11
Check method insert  put
• Signatures: put = proc (i: int); insert = proc (i: int)
• Pre-condition of put  pre-condition of insert
x : BSet put.pre [ A(xpre) / xpre ]  insert.pre
| A(spre).elems | < A(spre).bound
 i <= sp.limit  i >= 0
• NO! The subtype method has a stronger precondition, so it is not a subtype.
29 March 2001
CS 655: Lecture 18
12
Does this make sense?
• Intuition: subtype is unsafe, if there is
some program written for the supertype
that can tell the difference
• Here’s one:
put (999235);  insert (999235);
29 March 2001
CS 655: Lecture 18
13
uset  bag?
• A:ST
• A : Set  BBag
8
 s : Set; A (s) = < s, >
• Renaming:
– R(insert) = put
– R(size) = card
R(choose) = get
R(equal) = equal
• Check method choose  get (same as
bset)
29 March 2001
CS 655: Lecture 18
14
Check method insert  put
• Pre-condition of put  pre-condition of insert
x : BSet put.pre [ A(xpre) / xpre ] 
insert.pre = true
• Post-condition of insert  post-condition of put
insert.post  put.post [ A(xpre) / xpre, A(xpost) / xpost]
(spost.elements = spre.elements  { i })
 (bpost.elems = bpre.elems  { i }  bpost.bound = bpre.bound)
[ A(bpre) / bpre, A(bpost) / bpost]
recall: A (s) = < s, infinity>
so (spost.elems = spre.elems  { i }  infinity = infinity
29 March 2001
CS 655: Lecture 18
15
Check Invariant
• Need to show: IS  IT [ A(xp) / xp]
true  (| bp.elems | <= bp.bound) [ A(bp) / bp]
true  (| <s.elements, infinity>.elems | <=
<s.elements, infinity>.bound
true  true
• Similar for constraint
• uset is a subtype of bag! Yippee!
(Except: signature of equal should take a bag!)
29 March 2001
CS 655: Lecture 18
16
Summary Questions
• uset  bset?, bset  uset?
• Does the Liskov/Wing subtype relation
definition match intuition?
• Is it useful?
29 March 2001
CS 655: Lecture 18
17
Eiffel and I Can’t Get Up
Eiffel’s Type System
Normal Procedure Type Rule
f = proc (p1: P1, ..., pn: Pn) returns (X)
g = proc (p1: Q1, ..., pn: Qn) returns (Y)
Qi  Pi forall i in 1..n
XY
f g
Procedures are contravariant on
parameters, covariant on results.
29 March 2001
CS 655: Lecture 18
19
Eiffelling
How can Girl override set_roomate?
Covariance: (Eiffel)
set_roommate (Girl)
Skier
set_roommate (Boy)
set_roommate (Skier)
Contravariance: (Sather)
set_roommate (Athlete)
Novariance: (C++ (complicated), Java)
Boy
Girl
set_roommate (Skier)
Athlete
29 March 2001
CS 655: Lecture 18
20
Can’t Get Up?
Athlete
Skier
set_roommate (Skier)
Boy
s: skier; g: girl; b: boy;
s := g;
...
s.set_roommate (b);
Girl
set_roomate (Girl)
29 March 2001
CS 655: Lecture 18
21
Meyer’s Excuse
Strangely enough, some workers in the field have
been advocating a contravariant policy. Here it would
mean that if we go for example to class
RANKED_GIRL, where the result of roommate is
naturally redefined to be of type RANKED_GIRL, we
may for the argument of routine share use type GIRL,
or rather scaringly, SKIER of the most general kind.
One type that is never permitted in this case is
RANKED_GIRL! Here is what, under various
mathematical excuses, some professors have been
promoting. No wonder teenage pregnancies are on
the rise.
29 March 2001
CS 655: Lecture 18
22
What’s wrong with Meyer’s Rule?
• Disallow polymorphic catcalls:
s.f (t) where some subtype of type of s
hides f or changes covariantly type of
parameters of f.
• Violates useful notion of subtyping:
adding a new subtype breaks existing
programs!
– Eiffel compiler will complain for redefinition
29 March 2001
CS 655: Lecture 18
23
What does C++ really do?
• Can add covariant methods in subtype, but they
overload the original method, instead of
overriding it!
• Does this make sense?
29 March 2001
CS 655: Lecture 18
24
class skier {
public: virtual void set_roommate (class skier *s) { fprintf (stderr, "skier roomate!"); }
};
class girl : public skier {
void set_roommate (class girl *g) { fprintf (stderr, "girl roomate!"); }
};
class boy : public skier {
void set_roommate (class boy *b) { fprintf (stderr, "boy roomate!"); }
};
int main (void) {
girl *g = new girl (); boy *b = new boy (); skier *s;
s = g;
s->set_roommate (b);
g->set_roommate (b);
}
29 March 2001
CS 655: Lecture 18
25
Result
• Both g++ and MSVC++ produce compiletime errors for g->set_roommate (b)
skiers.C:27: no matching function for call to `girl::set_roommate (boy *&)'
skiers.C:9: candidates are: void girl::set_roommate(girl *)
• After removing this line, compiles okay,
produces: “skier roomate!” (calls the
superclass method)
• If girl::set_roommate (girl *) overloads, but
doesn’t override skier::set_roommate why
does this happen?
29 March 2001
CS 655: Lecture 18
26
Some C++ Facts
• 1996 Draft Standard is 680 pages long
– 50x more complex than Algol60! Is this progress?
• Current open issues list of Core Language
Issues contains 223 issues
– Compare to Knuth’s 9 ambiguities in Algol 60
• Current open issues list for standard library
(Revision 12) is 59 pages
• Good luck!
29 March 2001
CS 655: Lecture 18
27
Date: Fri, 03 Mar 2000 18:09:53 -0500
From: Avneesh Saxena <[email protected]>
To: [email protected]
Subject: C++: overriding problems!
Sir,
I am Avneesh, a graduate student in the CS Dept, Univ of
Virginia. I am currently taking a course on Programming
languages in which we are doing a detailed study of subclassing
mechanisms in computer languages. I have learned C++ from
your book "The C++ Pgm'ing Language" which is written in a very
clear and concise manner. Especially, the concepts are made clear
and ambiguties about language features have been discussed and
resolved in an appreciable manner.
However, I have run in a problem while trying to figure out what
this code would do:
29 March 2001
CS 655: Lecture 18
28
... (example same as ours but less of a social statement)
I have tried to run this code both through GCC v2.8.1 and MS-VC++, which
give the same results. It appears that while we would accept other() to be
accessible through the derived classes, the compiler doesn't find it.
The second (more serious)problem is when other(bPtr) is called, we
expect it to execute the function which has been defined in class B as it
overrides the function defines in class A as the type of the actual argument
matches this more closely; however, it executes the base classes function
(circumvents polymorphism!). I tried to check if this behavior was
consistent with the language definition but I failed to find anything which
would clarify things. So, I am left wondering whether this is a case of the
compiler not understanding the language and doing something wrong or is
it what the language desires?
I hope you will be able to clarify things for me,
Thanks,
Avs
29 March 2001
CS 655: Lecture 18
29
Subject: Re: C++: overriding problems!
Date: Sat, 4 Mar 2000 20:19:34 -0500 (EST)
From: Bjarne Stroustrup <[email protected]>
To: [email protected]
> ... (copy of Avneesh’s message elided)
Your problem is that you think that the two other() function overloads. They don’t functions in
different scope do not overload, so when you look at scope C::other(). If you want overloading
you'll have to explicitly do so in C.
One simple way of doing so is to say:
using B::other;
in C, but that's a relatively new feature
> I have tried to run this code both through GCC v2.8.1 and MS-VC++, which give the same
> results. It appear that while we would accept other() to be
> accessible through the derived classes, the compiler doesn't find it.
I think you mean "expect", but you expect wrongly.
> ... So, I am left wondering whether this is a case of the compiler not understanding the
> language and doing something wrong or is it what the language desires?
The compilers are wrong I suggest a re-read of the sections about
deriving classes in your textbook.
29 March 2001
CS 655: Lecture 18
30
Emailing Experts
• All of you should (soon if not already)
have email exchanges with experts
relevant to your projects
• One good email can save you reading
thousands of pages!
• Good to build your research contacts
29 March 2001
CS 655: Lecture 18
31
Date: Fri, 03 Mar 2000 18:09:53 -0500
From: Avneesh Saxena <[email protected]>
To: [email protected]
Subject: C++: overriding problems!
Be polite
Sir,
Introduce Yourself (be brief)
FlatteryI am
is Avneesh, a graduate student in the CS Dept,
DoUniv
yourof
always
a good
Virginia.
I am currently taking a course on Programming
homework first
languages
which we are doing a detailed study of subclassing
idea!
(okay toinlie
mechanisms
in computer languages. I have learned C++ from
a little
if
your book "The C++ Pgm'ing Language" which is written in a very
necessary)
clear and concise manner. Especially, the concepts are made clear
and ambiguties about language features have been discussed and
resolved in an appreciable manner.
However, I have run in a problem
whileask
trying
to figure
outspecific
what
Concisely
a clear
and
this code would do:
question.
29 March 2001
CS 655: Lecture 18
32
Charge
• Be ready for elevator speeches next
week:
– Convince the class your project is
interesting and worthwhile in 90 seconds
• Next time: pragmatic aspects of OO
languages - comparison of Sather,
Eiffel, Java and C++
29 March 2001
CS 655: Lecture 18
33