程序代写代做代考 android compiler IOS C Java Inheritance Readings: OOSCS2 Chapters 14 – 16

Inheritance Readings: OOSCS2 Chapters 14 – 16
EECS3311 M: Software Design Winter 2019
CHEN-WEI WANG

Aspects of Inheritance
Code Reuse
Substitutability
X Polymorphism and Dynamic Binding
X Sub-contracting
[ compile-time type checks ] [ runtime behaviour checks ]
2 of 63

Why Inheritance: A Motivating Example
Problem: A student management system stores data about students. There are two kinds of university students: resident students and non-resident students. Both kinds of students have a name and a list of registered courses. Both kinds of students are restricted to register for no more than 30 courses. When calculating the tuition for a student, a base amount is first determined from the list of courses they are currently registered (each course has an associated fee). For a non-resident student, there is a discount rate applied to the base amount to waive the fee for on-campus accommodation. For a resident student, there is a premium rate applied to the base amount to account for the fee for on-campus accommodation and meals. Tasks: Design classes that satisfy the above problem statement. At runtime, each type of student must be able to
register a course and calculate their tuition fee.
3 of 63

The COURSE Class
class
COURSE
create — Declare commands that can be used as constructors make
feature — Attributes title: STRING
fee: REAL
feature — Commands
make (t: STRING; f: REAL)
— Initialize a course with title ’t’ and fee ’f’.
do
title := t
fee := f end
end
4 of 63

No Inheritance: RESIDENT STUDENT Class
RESIDENT STUDENT
class
create make
feature — Attributes
name: STRING
courses: LINKED_LIST[COURSE]
premium rate: REAL
feature — Constructor make (n: STRING)
do name := n ; create courses.make end feature — Commands
set pr (r: REAL) do premium rate := r end
register (c: COURSE) do courses.extend (c) end feature — Queries
tuition: REAL local base: REAL do base := 0.0
across courses as c loop base := base + c.item.fee end
Result := base * premium rate
end end
5 of 63

No Inheritance: NON RESIDENT STUDENT Class
NON RESIDENT STUDENT
class
create make
feature — Attributes
name: STRING
courses: LINKED_LIST[COURSE]
discount rate: REAL
feature — Constructor make (n: STRING)
do name := n ; create courses.make end feature — Commands
set dr (r: REAL) do discount rate := r end
register (c: COURSE) do courses.extend (c) end feature — Queries
tuition: REAL local base: REAL do base := 0.0
across courses as c loop base := base + c.item.fee end
Result := base * discount rate end
end
6 of 63

No Inheritance: Testing Student Classes
test_students: BOOLEAN local
c1, c2: COURSE
jim: RESIDENT_STUDENT jeremy: NON_RESIDENT_STUDENT
do
create c1.make (“EECS2030”, 500.0) create c2.make (“EECS3311”, 500.0) create jim.make (“J. Davis”) jim.set_pr (1.25)
jim.register (c1)
jim.register (c2)
Result := jim.tuition = 1250
check Result end
create jeremy.make (“J. Gibbons”) jeremy.set_dr (0.75) jeremy.register (c1) jeremy.register (c2)
Result := jeremy.tuition = 750
end
7 of 63

No Inheritance:
Issues with the Student Classes
Implementations for the two student classes seem to work. But can you see any potential problems with it?
The code of the two student classes share a lot in common.
Duplicates of code make it hard to maintain your software!
This means that when there is a change of policy on the common part, we need modify more than one places.
 This violates the Single Choice Principle :
when a change is needed, there should be a single place (or a minimal number of places) where you need to make that change.
8 of 63

No Inheritance: Maintainability of Code (1)
What if a new way for course registration is to be implemented? e.g.,
register(Course c) do
if courses.count >= MAX_CAPACITY then — Error: maximum capacity reached.
else
courses.extend (c) end
end
We need to change the register commands in both student classes!
 Violation of the Single Choice Principle 9 of 63

No Inheritance: Maintainability of Code (2)
What if a new way for base tuition calculation is to be implemented?
e.g.,
tuition: REAL
local base: REAL
do base := 0.0
across courses as c loop base := base + c.item.fee end Result := base * inflation rate * …
end
We need to change the tuition query in both student classes.
 Violation of the Single Choice Principle 10 of 63

No Inheritance:
A Collection of Various Kinds of Students
How do you define a class StudentManagementSystem that contains a list of resident and non-resident students?
class STUDENT_MANAGEMENT_SYSETM
rs : LINKED_LIST[RESIDENT STUDENT]
nrs : LINKED_LIST[NON RESIDENT STUDENT]
add_rs (rs: RESIDENT STUDENT) do … end
add_nrs (nrs: NON RESIDENT STUDENT) do … end register_all (Course c) — Register a common course ’c’.
do
across rs as c loop c.item.register (c) end across nrs as c loop c.item.register (c) end
end end
But what if we later on introduce more kinds of students?
Inconvenient to handle each list of students, in pretty much the
same manner, separately! 11 of 63

Inheritance Architecture
inherit
STUDENT
inherit
RESIDENT STUDENT NON RESIDENT STUDENT
12 of 63

Inheritance: The STUDENT Parent Class
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
STUDENT
class
create make
feature — Attributes
name: STRING
courses: LINKED_LIST[COURSE]
feature — Commands that can be used as constructors.
make (n: STRING) do name := n ; create courses.make end feature — Commands
register (c: COURSE) do courses.extend (c) end feature — Queries
tuition: REAL local base: REAL do base := 0.0
across courses as c loop base := base + c.item.fee end
Result := base end
end
13 of 63

Inheritance:
The RESIDENT STUDENT Child Class
1 2 3 4 5 6 7 8 9
10 11
12 13 14 15
class
RESIDENT_STUDENT
inherit
STUDENT
redefine tuition end
create make
feature — Attributes
premium rate : REAL feature — Commands
set pr (r: REAL) do premium_rate := r end feature — Queries
tuition: REAL
local base: REAL
do base := Precursor ; Result := base * premium rate end
end
14 of 63
L3: RESIDENT STUDENT inherits all features from STUDENT.
There is no need to repeat the register command
L14: Precursor returns the value from query tuition in STUDENT.

Inheritance:
The NON RESIDENT STUDENT Child Class
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
class
NON_RESIDENT_STUDENT
inherit
STUDENT
redefine tuition end
create make
feature — Attributes
discount rate : REAL feature — Commands
set dr (r: REAL) do discount_rate := r end feature — Queries
tuition: REAL
local base: REAL
do base := Precursor ; Result := base * discount rate end
end
L3: NON RESIDENT STUDENT inherits all features from STUDENT. There is no need to repeat the register command
L14: Precursor returns the value from query tuition in STUDENT.
15 of 63

Inheritance Architecture Revisited
inherit
STUDENT
inherit
RESIDENT STUDENT NON RESIDENT STUDENT
The class that defines the common features (attributes, commands, queries) is called the parent , super , or
ancestor class.
Each “specialized” class is called a child , sub , or
descendent class. 16 of 63

Using Inheritance for Code Reuse
Inheritance in Eiffel (or any OOP language) allows you to:
X Factor out common features (attributes, commands, queries) in a
separate class.
e.g., the STUDENT class
X Define an “specialized” version of the class which:
inherits definitions of all attributes, commands, and queries e.g., attributes name, courses
e.g., command register
e.g., query on base amount in tuition
This means code reuse and elimination of code duplicates!
defines new features if necessary
e.g., set pr for RESIDENT STUDENT
e.g., set dr for NON RESIDENT STUDENT
redefines features if necessary
e.g., compounded tuition for RESIDENT STUDENT e.g., discounted tuition for NON RESIDENT STUDENT
17 of 63

Testing the Two Student Sub-Classes
test_students: BOOLEAN local
c1, c2: COURSE
jim: RESIDENT_STUDENT ; jeremy: NON_RESIDENT_STUDENT do
create c1.make (“EECS2030”, 500.0); create c2.make (“EECS3311”, 500.0) create jim.make (“J. Davis”)
jim.set_pr (1.25) ; jim.register (c1); jim.register (c2)
Result := jim.tuition = 1250
check Result end
create jeremy.make (“J. Gibbons”)
jeremy.set_dr (0.75); jeremy.register (c1); jeremy.register (c2) Result := jeremy.tuition = 750
end
The software can be used in exactly the same way as before (because we did not modify feature signatures).
But now the internal structure of code has been made
maintainable using . 18 of 63
inheritance

DbC: Contract View of Supplier
Any potential client who is interested in learning about the kind of services provided by a supplier can look through the
(without showing any implementation details):
contract view
class ACCOUNT create
make
feature — Attributes owner : STRING
balance : INTEGER feature — Constructors
make(nn: STRING; nb: INTEGER) require — precondition
positive balance: nb > 0
end feature — Commands
withdraw(amount: INTEGER) require — precondition
non negative amount: amount > 0
affordable amount: amount <= balance -- problematic, why? ensure -- postcondition balance deducted: balance = old balance - amount end invariant -- class invariant 19 of 63 positive balance: balance > 0
end

ES TEST: Expecting to Fail Postcondition (1) model
tests
feature ­­ Test Commands for Contract Violations test_withdraw_postcondition_violation
local
acc: BAD_ACCOUNT_WITHDRAW
do
create acc.make (“Alan”, 100)
­­ Violation of Postcondition
­­ with tag “balance_deduced” expected acc.withdraw (50)
end
ACCOUNT
feature ­­ Commands
withdraw (amount: INTEGER)
require
non_negative_amount: amount > 0
affordable_amount: amount ≤ balance do
balance := balance ­ amount
ensure
balance_deduced: balance = old balance ­ amount
end
BAD_ACCOUNT_WITHDRAW
feature ­­ Redefined Commands withdraw (amount: INTEGER) ++
do
Precursor (amount)
­­ Wrong Implementation balance := balance + 2 * amount
end
TEST_ACCOUNT
acc
20 of 63

ES TEST: Expecting to Fail Postcondition (2.1)
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
class
BAD_ACCOUNT_WITHDRAW
inherit
ACCOUNT
redefine withdraw end
create
make
feature — redefined commands withdraw(amount: INTEGER)
do
Precursor(amount)
— Wrong implementation
balance := balance + 2 * amount
end end
X L3–5: BAD ACCOUNT WITHDRAW.withdraw inherits postcondition from ACCOUNT.withdraw: balance = old balance – amount.
X L11 calls correct implementation from parent class ACCOUNT.
X L13 makes overall implementation incorrect. 21 of 63

ES TEST: Expecting to Fail Postcondition (2.2)
1 class TEST_ACCOUNT
2 inherit ES TEST
3 create make
4 feature — Constructor for adding tests 5 make
6 do
7
8
9 end
add violation case with tag (“balance_deducted”, agent test_withdraw_postcondition_violation)
10 feature — Test commands (test to fail) 11 test_withdraw_postcondition_violation 12 local
13
14 do
acc: BAD_ACCOUNT_WITHDRAW
15
16
17
18
19 end 20 end
comment (“test: expected postcondition violation of withdraw”) create acc.make (“Alan”, 100)
— Postcondition Violation with tag “balance_deduced” to occur. acc.withdraw (50)
22 of 63

Exercise
Recall from the “Writing Complete Postconditions” lecture:
class BANK
deposit_on_v5 (n: STRING; a: INTEGER)
do … — Put Correct Implementation Here. ensure

others unchanged :
across old accounts.deep twin as cursor all cursor.item.owner / n implies
cursor.item  account_of (cursor.item.owner) end
end end
How do you create a “bad” descendant of BANK that violates this postcondition?
class BAD_BANK_DEPOSIT
inherit BANK redefine deposit end feature — redefined feature
deposit_on_v5 (n: STRING; a: INTEGER) do Precursor (n, a)
accounts[accounts.lower].deposit(a)
end end
23 of 63

Static Type vs. Dynamic Type
In
X
object orientation , an entity has two kinds of types:
static type is declared at compile time [ unchangeable ]
An entity’s ST determines what features may be called upon it.
dynamic type is changeable at runtime In Java:
In Eiffel:
Student s = new Student(“Alan”);
Student rs = new ResidentStudent(“Mark”);
local s: STUDENT rs: STUDENT
do create {STUDENT} s.make (“Alan”)
create {RESIDENT STUDENT} rs.make (“Mark”)
24 of 63
X
X In Eiffel, the dynamic type can be omitted if it is meant to be the same as the static type:
local s: STUDENT
do create s.make (“Alan”)

Inheritance Architecture Revisited
register (Course c)
tuition: REAL
name: STRING
courses: LINKED_LIST[COUNRSE]
/* new features */
discount_rate: REAL set_dr (r: REAL)
/* redefined features */ tuition: REAL
STUDENT
/* new features */
premium_rate: REAL set_pr (r: REAL)
/* redefined features */ tuition: REAL
RESIDENT_STUDENT
NON_RESIDENT_STUDENT
s1,s2,s3: STUDENT ; rs: RESIDENT STUDENT ; nrs : NON RESIDENT STUDENT create {STUDENT} s1.make (“S1”)
create {RESIDENT STUDENT} s2.make (“S2”)
create {NON RESIDENT STUDENT} s3.make (“S3”)
create {RESIDENT STUDENT} rs.make (“RS”) create {NON RESIDENT STUDENT} nrs.make (“NRS”)
name
courses
reg
tuition
pr
set pr
dr
set dr
s1.


s2.


s3.


rs.



nrs.



25 of 63

Polymorphism: Intuition (1)
1 2 3 4 5 6 7 8 9
local
s: STUDENT
rs: RESIDENT_STUDENT do
create s.make (“Stella”) create rs.make (“Rachael”) rs.set_pr (1.25)
s := rs /* Is this valid? */ rs := s /* Is this valid? */
Which one of L8 and L9 is valid? Which one is invalid?
X L8: What kind of address can s store? [ STUDENT ]
 The context object s is expected to be used as: s.register(eecs3311) and s.tuition
X L9: What kind of address can rs store? [ RESIDENT STUDENT ]  The context object rs is expected to be used as:
rs.register(eecs3311) and rs.tuition
rs.set pr (1.50) [increase premium rate]
26 of 63

Polymorphism: Intuition (2)
1 2 3 4 5 6
local s: STUDENT ; rs: RESIDENT_STUDENT do create {STUDENT} s.make (“Stella”)
create {RESIDENT_STUDENT} rs.make (“Rachael”) rs.set_pr (1.25)
s := rs /* Is this valid? */
rs := s /* Is this valid? */
rs := s (L6) should be invalid:
s:STUDENT
rs:RESIDENT_STUDENT
STUDENT
name “Stella”
courses
RESIDENT_STUDENT


rs declared of type RESIDENT STUDENT
 calling rs.set pr(1.50) can be expected.
rs is now pointing to a STUDENT object.
Then, what would happen to rs.set pr(1.50)?
CRASH ì rs.premium rate is undefined!!
name courses premium_rate
“Rachael”
1.25
27 of 63

Polymorphism: Intuition (3)
1 2 3 4 5 6
local s: STUDENT ; rs: RESIDENT_STUDENT do create {STUDENT} s.make (“Stella”)
create {RESIDENT_STUDENT} rs.make (“Rachael”) rs.set_pr (1.25)
s := rs /* Is this valid? */
rs := s /* Is this valid? */
s := rs (L5) should be valid:
s:STUDENT
rs:RESIDENT_STUDENT
STUDENT
name “Stella”
courses
RESIDENT_STUDENT


Since s is declared of type STUDENT, a subsequent call s.set pr(1.50) is never expected.
s is now pointing to a RESIDENT STUDENT object. Then, what would happen to s.tuition?
name courses premium_rate
“Rachael”
1.25
28 of 63
OK ì s.premium rate is just never used!!

Dynamic Binding: Intuition (1)
1 2 3 4 5 6 7 8
local c : COURSE ; s : STUDENT
do crate c.make (“EECS3311”, 100.0)
create {RESIDENT STUDENT} rs.make(“Rachael”) create {NON RESIDENT STUDENT} nrs.make(“Nancy”) rs.set_pr(1.25); rs.register(c) nrs.set_dr(0.75); nrs.register(c)
; check .tuition = 125.0 end ; check .tuition = 75.0 end
s := rs;
s := nrs;
s
s
After s := rs (L7), s points to a RESIDENT STUDENT object.  Calling .tuition applies the premium rate.
29 of 63
s
rs:RESIDENT_STUDENT
s:STUDENT
nrs:NON_RESIDENT_STUDENT
RESIDENT_STUDENT
name courses
“Rachael”
premium_rate 1.25
NON_RESIDENT_STUDENT name “Nancy”
courses
discount_rate 0.75
COURSE title “EECS3311”
fee 100.0

Dynamic Binding: Intuition (2)
1 2 3 4 5 6 7 8
local c : COURSE ; s : STUDENT
do crate c.make (“EECS3311”, 100.0)
create {RESIDENT STUDENT} rs.make(“Rachael”) create {NON RESIDENT STUDENT} nrs.make(“Nancy”) rs.set_pr(1.25); rs.register(c) nrs.set_dr(0.75); nrs.register(c)
; check .tuition = 125.0 end ; check .tuition = 75.0 end
s := rs;
s := nrs;
s
s
After s:=nrs (L8), s points to a NON RESIDENT STUDENT object.  Calling .tuition applies the discount rate.
30 of 63
s
rs:RESIDENT_STUDENT
s:STUDENT
nrs:NON_RESIDENT_STUDENT
RESIDENT_STUDENT
name courses
“Rachael”
premium_rate 1.25
NON_RESIDENT_STUDENT name “Nancy”
courses
discount_rate 0.75
COURSE title “EECS3311”
fee 100.0

Multi-Level Inheritance Architecture (1)
31 of 63
DOMESTIC_STUDENT
STUDENT
FOREIGN_STUDENT
DOMESTIC_RESIDENT_STUDENT
DOMESTIC_NON_RESIDENT_STUDENT
FOREIGN_RESIDENT_STUDENT
FOREIGN_NON_RESIDENT_STUDENT

Multi-Level Inheritance Architecture (2)
SMART_PHONE
dial — basic feature surf_web — basic feature
IOS
surf_web — redefined using safari facetime — new feature
surf_web — redefined using firefox skype — new feature
ANDROID
IPHONE_6S
IPHONE_6S_PLUS
SAMSUNG
HTC
three_d_touch — new feature
side_sync — new feature
32 of 63
GALAXY_S6_EDGE
GALAXY_S6_EDGE_PLUS
HTC_ONE_A9
HTC_ONE_M9

Inheritance Forms a Type Hierarchy
A (data) type denotes a set of related runtime values.
X Every class can be used as a type: the set of runtime objects.
Use of inheritance creates a hierarchy of classes: X (Implicit) Root of the hierarchy is ANY.
X Each inherit declaration corresponds to an upward arrow.
X The inherit relationship is transitive: when A inherits B and B
inherits C, we say A indirectly inherits C.
e.g., Every class implicitly inherits the ANY class. Ancestor vs. Descendant classes:
X The ancestor classes of a class A are: A itself and all classes that A directly, or indirectly, inherits.
A inherits all features from its ancestor classes.
 A’s instances have a wider range of expected usages (i.e., attributes, queries, commands) than instances of its ancestor classes.
X The descendant classes of a class A are: A itself and all classes that directly, or indirectly, inherits A.
Code defined in A is inherited to all its descendant classes.
33 of 63

Inheritance Accumulates Code for Reuse
The lower a class is in the type hierarchy, the more code it accumulates from its ancestor classes:
X A descendant class inherits all code from its ancestor classes. X A descendant class may also:
Declare new attributes.
Define new queries or commands.
Redefine inheritedqueriesorcommands. Consequently:
X When being used as context objects ,
instances of a class’ descendant classes have a wider range of expected usages (i.e., attributes, commands, queries).
X When expecting an object of a particular class, we may substitute it with an object of any of its descendant classes.
X e.g., When expecting a STUDENT object, substitute it with either a RESIDENT STUDENT or a NON RESIDENT STUDENT object.
X Justification: A descendant class contains at least as many
features as defined in its ancestor classes (but not vice versa!). 34 of 63

Substitutions via Assignments
By declaring , reference variable v1 will store the address of an object of class C1 at runtime.
By declaring , reference variable v2 will store the address of an object of class C2 at runtime.
Assignment copies the address stored in v2 into v1. X v1 will instead point to wherever v2 is pointing to. [ object alias ]
v1:C1
v2:C2
v1:=v2
v1
v2
In such assignment , we say that we an object of type C1 with an object of type C2.
Substitutions are subject to rules! 35 of 63

C1

C2


v1:=v2
substitute

Rules of Substitution
Given an inheritance hierarchy:
1. When expecting an object of class A, it is safe to substitute it
with an object of any descendant class of A (including A). X e.g., When expecting an IOS phone, you can substitute it with
either an IPhone6s or IPhone6sPlus.
X ì Each descendant class of A is guaranteed to contain all code
of (non-private) attributes, commands, and queries defined in A. X  All features defined in A are guaranteed to be available in the
new substitute.
2. When expecting an object of class A, it is unsafe to substitute
it with an object of any .
X e.g., When expecting an IOS phone, you cannot substitute it with
just a SmartPhone, because the facetime feature is not
supported in an Android phone.
X ì Class A may have defined new features that do not exist in any
of its parent’s ancestor classes . 36 of 63
ancestor class of A’s parent

Reference Variable: Static Type
A reference variable’s static type is what we declare it to be.
X e.g., declares jim’s static type as STUDENT.
X e.g.,
declares a variable my phone of static type SmartPhone.
X The static type of a reference variable never changes.
For a reference variable v, its
A feature call v.m(. . . ) is compilable if m is defined in .
X e.g., After declaring , we may call register and tuition on jim
may not call set pr (specific to a resident student) or set dr
(specific to a non-resident student) on jim
X e.g., After declaring , we
jim:STUDENT
my phone:SMART PHONE
static type
.
C
defines the
expected usages of v as a context object
C
jim:STUDENT
my phone:SMART PHONE
37 of 63
may call dial and surf web on my phone
may not call facetime (specific to an IOS phone) or skype (specific to an Android phone) on my phone

Reference Variable: Dynamic Type
A reference variable’s dynamic type is the type of object that it is currently pointing to at runtime.
X The dynamic type of a reference variable may change whenever we re-assign that variable to a different object.
X There are two ways to re-assigning a reference variable.
38 of 63

Reference Variable: Changing Dynamic Type (1)
Re-assigning a reference variable to a newly-created object:
X Substitution Principle : the new object’s class must be a descendant class of the reference variable’s static type.
X e.g., Given the declaration :
changes the dynamic type of jim to RESIDENT STUDENT.
changes the dynamic type of jim to NON RESIDENT STUDENT.
X e.g., Given an alternative declaration :
e.g., is illegal
because STUDENT is not a descendant class of the static type of jim (i.e., RESIDENT STUDENT).
jim:STUDENT
create {RESIDENT STUDENT} jim.make(“Jim”)
create {NON RESIDENT STUDENT} jim.make(“Jim”)
jim:RESIDENT STUDENT
create {STUDENT} jim.make(“Jim”)
39 of 63

Reference Variable: Changing Dynamic Type (2)
Re-assigning a reference variable v to an existing object that is referenced by another variable other (i.e., v := other):
X Substitution Principle : the static type of other must be a descendant class of v’s static type.
X e.g.,
40 of 63
jim: STUDENT ; rs: RESIDENT STUDENT; nrs: NON RESIDENT STUDENT create {STUDENT} jim.make (…)
create {RESIDENT STUDENT} rs.make (…)
create {NON RESIDENT STUDENT} nrs.make (…)
rs := jim  nrs := jim  jim := rs  changes the dynamic type of jim to the dynamic type of rs
jim := nrs  changes the dynamic type of jim to the dynamic type of nrs

Polymorphism and Dynamic Binding (1)
Polymorphism : An object variable may have “multiple possible
shapes” (i.e., allowable dynamic types).
X Consequently, there are multiple possible versions of each feature
that may be called.
e.g., 3 possibilities of tuition on a STUDENT reference variable: In STUDENT: base amount
In RESIDENT STUDENT: base amount with premium rate
In NON RESIDENT STUDENT: base amount with discount rate
Dynamic binding : When a feature m is called on an object variable, the version of m corresponding to its “current shape” (i.e., one defined in the dynamic type of m) will be called.
jim: STUDENT; rs: RESIDENT STUDENT; nrs: NON STUDENT create {RESIDENT STUDENT} rs.make (…)
create {NON RESIDENT STUDENT} nrs.nrs (…)
jim := rs
jim.tuitoion; /* version in RESIDENT STUDENT */ jim := nrs
jim.tuition; /* version in NON RESIDENT STUDENT */
41 of 63

Polymorphism and Dynamic Binding (2.1)
1 2 3 4 5 6 7 8 9
10 11 12 13 14
test_polymorphism_students
local
jim: STUDENT
rs: RESIDENT STUDENT
nrs: NON RESIDENT STUDENT
do
create {STUDENT} jim.make (“J. Davis”)
create {RESIDENT STUDENT} rs.make (“J. Davis”) create {NON RESIDENT STUDENT} nrs.make (“J. Davis”) jim := rs 
rs := jim 
jim := nrs 
rs := jim 
end
In (L3, L7), (L4, L8), (L5, L9), ST = DT , so we may abbreviate: L7:
L8:
L9: 42 of 63
create jim.make (“J. Davis”)
create rs.make (“J. Davis”)
create nrs.make (“J. Davis”)

Polymorphism and Dynamic Binding (2.2)
test_dynamic_binding_students: BOOLEAN local
jim: STUDENT
rs: RESIDENT_STUDENT
nrs: NON_RESIDENT_STUDENT c: COURSE
do
create c.make (“EECS3311”, 500.0)
create {STUDENT} jim.make (“J. Davis”)
create {RESIDENT STUDENT} rs.make (“J. Davis”) rs.register (c)
rs.set_pr (1.5)
jim := rs
Result := jim.tuition = 750.0
check Result end
create {NON RESIDENT STUDENT} nrs.make (“J. Davis”) nrs.register (c)
nrs.set_dr (0.5)
jim := nrs
Result := jim.tuition = 250.0
end
43 of 63

Reference Type Casting: Motivation
1 2 3 4
local jim: STUDENT; rs: RESIDENT STUDENT
do create {RESIDENT STUDENT} jim.make (“J. Davis”)
rs := jim rs.setPremiumRate(1.5)
Line 2 is legal: RESIDENT_STUDENT is a descendant class of the static type of jim (i.e., STUDENT).
Line 3 is illegal: jim’s static type (i.e., STUDENT) is not a descendant class of rs’s static type (i.e., RESIDENT_STUDENT). Eiffel compiler is unable to infer that jim’s in
Line 4 is RESIDENT_STUDENT. [ ] Force the Eiffel compiler to believe so, by replacing L3, L4 by a
(which changes the ST of jim):
44 of 63
dynamic type
Undecidable
type cast
temporarily
check attached {RESIDENT STUDENT} jim as rs_jim then rs := rs_jim
rs.set_pr (1.5)
end

1 2 3 4
Reference Type Casting: Syntax
check attached {RESIDENT STUDENT} jim as rs_jim then rs := rs_jim
rs.set_pr (1.5)
end
L1 is an assertion: X
that is to be evaluated at .
If it evaluates to true, then the
of assigning “the cast version” of jim to a new variable rs jim. If it evaluates to false, then a runtime assertion violation occurs.
attached RESIDENT STUDENT jim
is a Boolean expression
runtime
as rs jim
expression has the effect
Dynamic Binding : Line 4 executes the correct version of set pr. It is equivalent to the following Java code:
if(jim instanceof ResidentStudent) { ResidentStudent rs = (ResidentStudent) jim; rs.set_pr(1.5);
}
else { throw new Exception(“Cast Not Done.”); }
45 of 63
X

Notes on Type Cast (1)
Given v of static type ST, it is compilable to cast v to C , as
long as C is a descendant or ancestor class of ST . Why Cast?
X Without cast, we can only call features defined in ST on v.
X Bycastingv to C ,wechangethestatictypeofv fromST to C .
 All features that are defined in C can be called.
my_phone: IOS
create {IPHONE 6S PLUS} my_phone.make
— can only call features defined in IOS on myPhone
— dial, surf_web, facetime  three_d_touch, skype  check attached {SMART PHONE} my_phone as sp then
— can now call features defined in SMART_PHONE on sp
— dial, surf_web  facetime, three_d_touch, skype  end
check attached {IPHONE 6S PLUS} my_phone as ip6s_plus then
— can now call features defined in IPHONE_6S_PLUS on ip6s_plus — dial, surf_web, facetime, three_d_touch  skype 
end
46 of 63

Notes on Type Cast (2)
A cast being compilable is not necessarily runtime-error-free! A cast triggers an assertion violation if C is not along the ancestor path of v’s DT .
test_smart_phone_type_cast_violation local mine: ANDROID
do create {SAMSUNG} mine.make
— ST of mine is ANDROID; DT of mine is SAMSUNG
check attached {SMART PHONE} mine as sp then … end — ST of sp is SMART_PHONE; DT of sp is SAMSUNG
check attached {SAMSUNG} mine as samsung then … end — ST of samsung is SAMSNG; DT of samsung is SAMSUNG check attached {HTC} mine as htc then … end
— Compiles ì HTC is descendant of mine’s ST (ANDROID)
— Assertion violation
— ì HTC is not ancestor of mine’s DT (SAMSUNG)
check attached {GALAXY S6 EDGE} mine as galaxy then … end
— Compiles ì GALAXY_S6_EDGE is descendant of mine’s ST (ANDROID) — Assertion violation
— ì GALAXY_S6_EDGE is not ancestor of mine’s DT (SAMSUNG) end
check attached {C} v as …
47 of 63

Compilable Cast vs. Exception-Free Cast (1)
1 2 3 4 5
class A end
class B inherit A end class C inherit B end class D inherit A end
local b: B ; d: D do
create {C} b.make
check attached {D} b as temp then d := temp end end
AfterL3: b’sST isBandb’sDT isC. Does L4 compile?
48 of 63
[ NO ] ì cast type D is neither an ancestor nor a descendant of b’s ST B

1 2 3 4 5
Compilable Cast vs. Exception-Free Cast (2)
class A end
class B inherit A end class C inherit B end class D inherit A end
local b: B ; d: D do
create {C} b.make
check attached {D} b as temp then d := temp end end
Would the following fix L4?
check attached {A} b as temp1 then
check attached {D} temp1 as temp2 then d := temp2 end
end
YES ì cast type D is an ancestor of b’s cast, temporary ST A What happens when executing this fix?
Assertion Violation ì cast type D not an ancestor of temp1’s DT C 49 of 63

Polymorphism: Feature Call Arguments (1)
1 2 3 4 5
class STUDENT_MANAGEMENT_SYSTEM {
ss : ARRAY[STUDENT] — ss[i] has static type Student add_s (s: STUDENT) do ss[0] := s end
add_rs (rs: RESIDENT STUDENT) do ss[0] := rs end add_nrs (nrs: NON RESIDENT STUDENT) do ss[0] := nrs end
L4: is valid. ì RHS’s ST RESIDENT STUDENT is a descendant class of LHS’s ST STUDENT.
Say we have a STUDENT MANAGEMENT SYSETM object sms:
X ì call by value , attempts the following assignment (i.e., replace parameter rs by a copy of argument o):
X Whether this argument passing is valid depends on o’s static type. Rule: In the signature of a feature m, if the type of a parameter is class C, then we may call feature m by passing objects whose
static types are C’s descendants. 50 of 63
ss[0]:=rs
sms.add rs(o)
rs := o

Polymorphism: Feature Call Arguments (2)
test_polymorphism_feature_arguments
local
s1, s2, s3: STUDENT
rs: RESIDENT STUDENT ; nrs: NON RESIDENT STUDENT sms: STUDENT_MANAGEMENT_SYSTEM
do
create sms.make
create {STUDENT} s1.make (“s1”)
create {RESIDENT_STUDENT} s2.make (“s2”)
create {NON_RESIDENT_STUDENT} s3.make (“s3”)
create {RESIDENT_STUDENT} rs.make (“rs”)
create {NON_RESIDENT_STUDENT} nrs.make (“nrs”)
sms.add_s (s1)  sms.add_s (s2)  sms.add_s (s3)  sms.add_s (rs)  sms.add_s (nrs) 
sms.add_rs (s1)  sms.add_rs (s2)  sms.add_rs (s3)  sms.add_rs (rs)  sms.add_rs (nrs) 
sms.add_nrs (s1)  sms.add_nrs (s2)  sms.add_nrs (s3)  sms.add_nrs (rs)  sms.add_nrs (nrs) 
end
51 of 63

Why Inheritance:
A Polymorphic Collection of Students
How do you define a class STUDENT MANAGEMENT SYSETM that contains a list of resident and non-resident students?
class STUDENT_MANAGEMENT_SYSETM students: LINKED_LIST[STUDENT] add_student(s: STUDENT)
do
students.extend (s) end
registerAll (c: COURSE) do
across
students as s
loop
s.item.register (c) end
end end
52 of 63

Polymorphism and Dynamic Binding: A Polymorphic Collection of Students
test_sms_polymorphism: BOOLEAN local
rs: RESIDENT_STUDENT
nrs: NON_RESIDENT_STUDENT
c: COURSE
sms: STUDENT_MANAGEMENT_SYSTEM
do
create rs.make (“Jim”)
rs.set_pr (1.5)
create nrs.make (“Jeremy”)
nrs.set_dr (0.5)
create sms.make
sms.add_s (rs)
sms.add_s (nrs)
create c.make (“EECS3311”, 500)
sms.register_all (c)
Result := sms.ss[1].tuition = 750 and sms.ss[2].tuition = 250
end
53 of 63

Polymorphism: Return Values (1)
1 2 3 4 5 6 7 8 9
10 11 12
class STUDENT_MANAGEMENT_SYSTEM { ss: LINKED_LIST[STUDENT]
add_s (s: STUDENT)
do
ss.extend (s) end
get_student(i: INTEGER): STUDENT require 1 <= i and i <= ss.count do Result := ss[i] end end L2: ST of each stored item (ss[i]) in the list: L3: ST of input parameter s: L7: ST of return value (Result) of get student: L11: ss[i]’s ST is descendant of Result’ ST . Question: What can be the dynamic type of s after Line 11? Answer: All descendant classes of Student. 54 of 63 [STUDENT] [STUDENT] [STUDENT] Polymorphism: Return Values (2) 1 2 3 4 5 6 7 8 9 10 11 12 13 test_sms_polymorphism: BOOLEAN local rs: RESIDENT_STUDENT ; nrs: NON_RESIDENT_STUDENT c: COURSE ; sms: STUDENT_MANAGEMENT_SYSTEM do create rs.make ("Jim") ; rs.set_pr (1.5) create nrs.make ("Jeremy") ; nrs.set_dr (0.5) create sms.make ; sms.add_s (rs) ; sms.add_s (nrs) create c.make ("EECS3311", 500) ; sms.register_all (c) Result := get_student(1).tuition = 750 and get_student(2).tuition = 250 end L11: get student(1)’s dynamic type? L11: Version of tuition? L12: get student(2)’s dynamic type? L12: Version of tuition? 55 of 63 [RESIDENT_STUDENT] [RESIDENT_STUDENT] [NON_RESIDENT_STUDENT] [NON_RESIDENT_STUDENT] Design Principle: Polymorphism When declaring an attribute  Choose static type which “accumulates” all features that you predict you will want to call on a. e.g., Choose if you do not intend to be specific about which kind of student s might be.  Let dynamic binding determine at runtime which version of tuition will be called. What if after declaring you find yourself often needing to cast s to RESIDENT STUDENT in order to access premium rate?  Your design decision should have been: Same design principle applies to: X Type of feature parameters: X Type of queries: 56 of 63 s: STUDENT T s: STUDENT a: T check attached {RESIDENT_STUDENT} s as rs then rs.set_pr(...) end s:RESIDENT_STUDENT f(a: T) q(...): T Static Type vs. Dynamic Type: When to consider which? Whether or not an OOP code compiles depends only on the static types of relevant variables. ì Inferring the dynamic type statically is an undecidable problem that is inherently impossible to solve. The behaviour of Java code being executed at runtime e.g., which version of method is called e.g., if a check attached {...} as ... then ... end assertion error will occur depends on the dynamic types of relevant variables.  Best practice is to visualize how objects are created (by drawing boxes) and variables are re-assigned (by drawing arrows). 57 of 63 Summary: Type Checking Rules CODE CONDITION TO BE TYPE CORRECT x := y y’s ST a descendant of x’s ST x.f(y) Feature f defined in x’s ST y’s ST a descendant of f’s parameter’s ST z := x.f(y) Feature f defined in x’s ST y’s ST a descendant of f’s parameter’s ST ST of m’s return value a descendant of z’s ST check attached {C} y then ... end C an ancestor or a descendant of y’s ST check attached {C} y as temp then x := temp end C an ancestor or a descendant of y’s ST C a descendant of x’s ST check attached {C} y as temp then x.f(temp) end C an ancestor or a descendant of y’s ST Feature f defined in x’s ST C a descendant of f’s parameter’s ST check attached {C} y then . . . end Even if compiles, a runtime assertion error occurs if C is not an ancestor of y’s DT ! 58 of 63 Index (1) Aspects of Inheritance Why Inheritance: A Motivating Example The COURSE Class No Inheritance: No Inheritance: No Inheritance: No Inheritance: Issues with the No Inheritance: RESIDENT STUDENT Class NON RESIDENT STUDENT Class Testing Student Classes Student Classes Maintainability of Code (1) Maintainability of Code (2) No Inheritance: No Inheritance: A Collection of Various Kinds of Students Inheritance Architecture Inheritance: The STUDENT Parent Class 59 of 63 Index (2) Inheritance: The RESIDENT STUDENT Child Class Inheritance: The NON RESIDENT STUDENT Child Class Inheritance Architecture Revisited Using Inheritance for Code Reuse Testing the Two Student Sub-Classes DbC: Contract View of Supplier ES TEST: Expecting to Fail Postcondition (1) ES TEST: Expecting to Fail Postcondition (2.1) ES TEST: Expecting to Fail Postcondition (2.2) Exercise Static Type vs. Dynamic Type Inheritance Architecture Revisited Polymorphism: Intuition (1) 60 of 63 Index (3) Polymorphism: Intuition (2) Polymorphism: Intuition (3) Dynamic Binding: Intuition (1) Dynamic Binding: Intuition (2) Multi-Level Inheritance Architecture (1) Multi-Level Inheritance Architecture (2) Inheritance Forms a Type Hierarchy Inheritance Accumulates Code for Reuse Substitutions via Assignments Rules of Substitution Reference Variable: Static Type Reference Variable: Dynamic Type Reference Variable: Changing Dynamic Type (1) 61 of 63 Index (4) Reference Variable: Changing Dynamic Type (2) Polymorphism and Dynamic Binding (1) Polymorphism and Dynamic Binding (2.1) Polymorphism and Dynamic Binding (2.2) Reference Type Casting: Motivation Reference Type Casting: Syntax Notes on Type Cast (1) Notes on Type Cast (2) Compilable Cast vs. Exception-Free Cast (1) Compilable Cast vs. Exception-Free Cast (2) Polymorphism: Feature Call Arguments (1) Polymorphism: Feature Call Arguments (2) 62 of 63 Index (5) Why Inheritance: A Polymorphic Collection of Students Polymorphism and Dynamic Binding: A Polymorphic Collection of Students Polymorphism: Return Values (1) Polymorphism: Return Values (2) Design Principle: Polymorphism Static Type vs. Dynamic Type: When to consider which? Summary: Type Checking Rules 63 of 63