Proper Inheritance John Lakos Tuesday, May 10, 2016

1

Copyright Notice © 2016 Bloomberg L.P. Permission is granted to copy, distribute, and display this material, and to make derivative works and commercial use of it. The information in this material is provided "AS IS", without warranty of any kind. Neither Bloomberg nor any employee guarantees the correctness or completeness of such information. Bloomberg, its employees, and its affiliated entities and persons shall not be liable, directly or indirectly, in any way, for any inaccuracies, errors or omissions in such information. Nothing herein should be interpreted as stating the opinions, policies, recommendations, or positions of Bloomberg.

2

Abstract All essential behavior of our software must be documented, and yet there are important advantages, with respect to development, verification and testing, performance, and stability, for leaving the behavior for some combinations of inputs and initial conditions undefined. What is and is not defined behavior should therefore be readily discernible from the contract, especially when creating contracts that must span classes related by inheritance.

In this two-part talk, we begin by reviewing components, interfaces and contracts in general, and the significance of narrow versus wide contracts. In the second part, we go on to explore three kinds of inheritance: (1) Interface Inheritance resulting from pure-virtual functions, (2) Structural Inheritance resulting from non-virtual functions, and (3) Implementation Inheritance resulting from non-pure virtual functions. Proper contracts involving each of these distinct forms have different criteria that must be addressed. The three kinds of inheritance are compared, and their relative utility is explained. What's more, several common uses of inheritance that are provably improper are summarily debunked. 3

What’s The Problem?

4

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

5

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional: • It involves many subtle logical and physical aspects.

6

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional: • It involves many subtle logical and physical aspects. • It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components.

7

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional: • It involves many subtle logical and physical aspects. • It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components. • It requires the designer to delineate logical behavior precisely, while managing the physical dependencies on other subordinate components.

8

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional: • It involves many subtle logical and physical aspects. • It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components. • It requires the designer to delineate logical behavior precisely, while managing the physical dependencies on other subordinate components. • It requires attention to numerous logical and physical rules that govern sound software design. 9

Purpose of this Talk

10

Purpose of this Talk Review:

11

Purpose of this Talk Review: 1. Components – Our fundamental unit of logical and physical design

12

Purpose of this Talk Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts

(in general)

13

Purpose of this Talk Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts (in general) 3. Narrow versus Wide contracts (in particular)

14

Purpose of this Talk Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts (in general) 3. Narrow versus Wide contracts (in particular)

4. Explore these basic ideas in the context inheritance. 15

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

16

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

17

1. Components (review)

Logical versus Physical Design What distinguishes Logical from Physical Design?

Logical physical

18

1. Components (review)

Logical versus Physical Design What distinguishes Logical from Physical Design?

Logical physical

Logical: Classes and Functions 19

1. Components (review)

Logical versus Physical Design What distinguishes Logical from Physical Design?

Logical physical

Logical: Classes and Functions Physical: Files and Libraries 20

1. Components (review)

Logical versus Physical Design Logical content aggregated into a Physical hierarchy of components c a

b

21

1. Components (review)

Component: Uniform Physical Structure A Component Is Physical // component.t.cpp #include

// ... int main(...) { //...

// component.h

// component.cpp #include

// ...

// ...

//-- END OF FILE --

//-- END OF FILE --

} //-- END OF FILE --

component.t.cpp

component.h component

component.cpp 22

1. Components (review)

Component: Uniform Physical Structure Implementation // component.t.cpp #include

// ... int main(...) { //...

// component.h

// component.cpp #include

// ...

// ...

//-- END OF FILE --

//-- END OF FILE --

} //-- END OF FILE --

component.t.cpp

component.h component

component.cpp 23

1. Components (review)

Component: Uniform Physical Structure Header // component.t.cpp #include

// ... int main(...) { //...

// component.h

// component.cpp #include

// ...

// ...

//-- END OF FILE --

//-- END OF FILE --

} //-- END OF FILE --

component.t.cpp

component.h component

component.cpp 24

1. Components (review)

Component: Uniform Physical Structure Test Driver // component.t.cpp #include

// ... int main(...) { //...

// component.h

// component.cpp #include

// ...

// ...

//-- END OF FILE --

//-- END OF FILE --

} //-- END OF FILE --

component.t.cpp

component.h component

component.cpp 25

1. Components (review)

Component: Uniform Physical Structure The Fundamental Unit of Design // component.t.cpp #include

// ... int main(...) { //...

// component.h

// component.cpp #include

// ...

// ...

//-- END OF FILE --

//-- END OF FILE --

} //-- END OF FILE --

component.t.cpp

component.h component

component.cpp 26

1. Components (review)

Component: Not Just a .h/.cpp Pair

my::Widget

my_widget 27

1. Components (review)

Component: Not Just a .h/.cpp Pair

28

1. Components (review)

Component: Not Just a .h/.cpp Pair 1.

The .cpp file includes its .h file as the first substantive line of code.

29

1. Components (review)

Component: Not Just a .h/.cpp Pair The .cpp file includes its .h file as the first substantive line of code. 2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file. 3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component. 4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration. 1.

30

1. Components (review)

Component: Not Just a .h/.cpp Pair The .cpp file includes its .h file as the first substantive line of code. 2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file. 3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component. 4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration. 1.

We could easily spend 20 minutes on this slide alone!

31

Avoid Global Namespace Pollution

1. Components Achieve (review)

Enable Efficient Extraction of Physical Dependencies

Component: Not Just a .h/.cpp Pair Logical/Physical Modularity

The .cpp file includes its .h file as the first substantive line of code. 2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file. 3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component. 4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration. 1.

32

Avoid Global Namespace Pollution

1. Components Achieve (review)

Enable Efficient Extraction of Physical Dependencies

Component: Not Just a .h/.cpp Pair Logical/Physical Modularity

The .cpp file includes its .h file as the first substantive line of code. 2. All logical constructs having external linkage For much defined in a .cpp file aremore declaredsee in the corresponding .h file. 3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component. 4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration. 1.

ADVANCED LEVELIZATION TECHNIQUES

33

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link Underscore Implies Component-Local Class

Point

Shape

34

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Is-A

35

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Is-A

36

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Is-A

37

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Is-A

38

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Is-A

39

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Uses-in-the-Implementation

Is-A

40

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Uses-in-the-Implementation

Is-A

41

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Shape

Uses-in-the-Interface Uses-in-the-Implementation

Is-A

42

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

Uses in name only 43 Is-A

1. Components (review)

Logical Relationships Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

Uses in name only 44 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

Uses in name only 45 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 46 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 47 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 48 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 49 Is-A

1. Components (review)

Implied Dependency Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 50 Is-A

1. Components (review)

Level Numbers Polygon

PointList

PointList_Link

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 51 Is-A

1. Components (review)

Level Numbers Polygon

PointList

PointList_Link

1

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape Depends-On Uses in name only 52 Is-A

1. Components (review)

Level Numbers Polygon

PointList

PointList_Link

1

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

1

Depends-On Uses in name only 53 Is-A

1. Components (review)

Level Numbers 2

Polygon

PointList

PointList_Link

1

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

1

Depends-On Uses in name only 54 Is-A

1. Components (review)

Level Numbers 2

3

Polygon

PointList

PointList_Link

1

Point

Uses-in-the-Interface Uses-in-the-Implementation

Shape

1

Depends-On Uses in name only 55 Is-A

1. Components (review)

Essential Physical Design Rules

56

1. Components (review)

Essential Physical Design Rules

There are two:

57

1. Components (review)

Essential Physical Design Rules

There are two:

1.No Cyclic Physical Dependencies! 58

1. Components (review)

Essential Physical Design Rules

There are two:

1.No Cyclic Physical Dependencies! 2.No Long-Distance Friendships!

59

1. Components (review)

End of Section

Questions?

1. Components (review)

What Questions are we Answering? • What distinguishes Logical and Physical Design? • What is the first of the (four) fundamental properties of a .h /.cpp pair that make it a component? • Which of these fundamental properties helps us extract physical dependencies efficiently? Extra credit: Why? How? • What are the (four) logical-relationship annotations? • Which logical relationship does not imply a physical one? • How do we infer physical relationships (Depends-On) from logical ones? • What do we mean by the term level number? • What are the (two) quintessential physical design rules? 61

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

62

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

63

2. Interfaces and Contracts (review)

Interfaces and Contracts What do we mean by Interface versus Contract for

• A Function? • A Class? • A Component? 64

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

65

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

Types Used In the Interface

66

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 67

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

68

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ Public // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); Interface // Create a date having the value of the specified ‘original’ date. // … };

69

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

70

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

71

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

72

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //… public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

73

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’. 74

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; “Public” bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value.

Interface

bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’. 75

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’. 76

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’. 77

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates do not have the // same value, and ‘false’ otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’. 78

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … }; bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates do not have the // same value, and ‘false’ otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’, and return a reference to ‘stream’. 79

2. Interfaces and Contracts (review)

Preconditions and Postconditions

80

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function

81

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

82

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

83

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Precondition 84

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Precondition For a Stateless Function: Restriction on syntactically legal inputs. 85

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

86

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Postcondition 87

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Postcondition For a Stateless Function: What it “returns.”

88

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method

89

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined.

90

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined. Postconditions: What must happen as a function of (object) state and input if all Preconditions are satisfied. 91

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined. Postconditions: What must happen as a function of (object) state and input if all Preconditions are satisfied. 92

Note that Essentialand Behavior refers 2. Interfaces Contracts (review)to a superset of Postconditions that includes Preconditions and Postconditions behavioral guarantees, such as runtime complexity.

Object Method

Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined. Postconditions: What must happen as a function of (object) state and method inputs if all preconditions are satisfied. Observation By

Kevlin Henny

93

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior Not Undefined Behavior

Undefined Behavior 94

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior Essential Behavior

Undefined Behavior 95

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior Defined but not Essential Essential Behavior

Undefined Behavior 96

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior Defined but not Essential

Unspecified and Implementation -dependent

Essential Behavior

Undefined Behavior 97

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 98

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 99

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 100

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 101

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 102

2. Interfaces and Contracts (review)

Any Preconditions and Postconditions Undefined Behavior?

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 103

2. Interfaces and Contracts (review)

Any Preconditions and Postconditions Non-Essential Behavior?

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 104

Hint

2. Interfaces and Contracts (review)

Any Preconditions and Postconditions Non-Essential Behavior?

Defined & Essential Behavior std::ostream& print(std::ostream& stream, int level = 0, int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. 105

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 106

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior class Date { Any // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

Undefined Behavior?

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 107

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior class Date { Any // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

Undefined Behavior?

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 108

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 109

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Defined & Essential Behavior class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

Any public: Undefined Date(int year, int month, int day); // Create a valid date from the specified Behavior? ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 110

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 111

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 112

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 113

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 114

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 115

2. Interfaces and Contracts (review)

Preconditions and Postconditions

(Object) Invariants class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive. //…

public: Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

};

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … 116

2. Interfaces and Contracts (review)

Design by Contract

117

2. Interfaces and Contracts (review)

Design by Contract

(DbC) “If you give me valid input*, I will behave as advertised; otherwise, all bets are off!” *including state 118

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 119

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 120

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 121

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 122

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 123

2. Interfaces and Contracts (review)

Design by Contract

Documentation There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that… 124

2. Interfaces and Contracts (review)

Design by Contract

Verification Invariants: Assert invariants in the destructor.

125

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: Invariants: Assert invariants in the destructor.

126

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Invariants: Assert invariants in the destructor.

127

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode). Invariants: Assert invariants in the destructor. 128

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode). Postconditions: Invariants: Assert invariants in the destructor. 129

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode). Postconditions: Component-level test drivers. Invariants: Assert invariants in the destructor. 130

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode). Postconditions: Component-level test drivers. Invariants: Assert invariants in the destructor. 131

2. Interfaces and Contracts (review)

Design by Contract

Verification Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode). Postconditions: Component-level test drivers. Invariants: Assert invariants in the destructor. 132

2. Interfaces and Contracts (review)

Contracts and Exceptions Preconditions always Imply Postconditions:

133

2. Interfaces and Contracts (review)

Contracts and Exceptions Preconditions always Imply Postconditions:  If a function cannot satisfy its contract (given valid preconditions) it

must not return normally.

134

2. Interfaces and Contracts (review)

Contracts and Exceptions Preconditions always Imply Postconditions:  If a function cannot satisfy its contract (given valid preconditions) it

must not return normally.

 abort() should be considered a viable alternative to throw in virtually all cases (if exceptions are disabled).

135

2. Interfaces and Contracts (review)

Contracts and Exceptions Preconditions always Imply Postconditions:  If a function cannot satisfy its contract (given valid preconditions) it

must not return normally.

 abort() should be considered a viable alternative to throw in virtually all cases (if exceptions are disabled).  Good library components are exception agnostic (via RAII). 136

2. Interfaces and Contracts (review)

End of Section

Questions? 137

2. Interfaces and Contracts (review)

What Questions are we Answering? • What do we mean by Interface versus Contract for a function, a class, or a component? • What do we mean by preconditions, postconditions, and invariants? • What do we mean by essential & undefined behavior? • Must the code itself preserve invariants even if one or more preconditions of the contract are violated? • What is the idea behind Design-by-Contract (DbC)? • How do we document the contract for a function? • How can clients ensure that preconditions are satisfied? • How do we guarantee that postconditions are satisfied? • How can we test to make sure invariants are preserved? • What must be true if a client satisfies all preconditions? 138

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

139

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

140

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

141

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms:

142

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms: •Fat Interface (4. Proper Inheritance)

143

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms: •Fat Interface (4. Proper Inheritance) •Large (Non-Primitive) Interface 144

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms: •Fat Interface (4. Proper Inheritance) •Large (Non-Primitive) Interface •Wide Contract

145

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

146

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

147

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

How about it must return 0? 148

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { if (!s) return 0; Wide // … }

How about it must return 0? 149

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { if (!s) return 0; Wide // … Likely to mask a defect }

How about it must return 0? 150

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { if (!s) return 0; Wide // … Likely to mask a defect }

How about it must return 0? 151

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

152

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

153

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { assert(s); Narrow // … }

154

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { Narrow

// … }

155

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s) { Narrow

// … }

156

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should Date::setDate(int, int, int); Return a status?

157

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should Date::setDate(int, int, int); Return a status?

158

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)! date.setDate(3, 8, 59); Therefore, why should I bother to check status? date.setDate(1959, 3, 8); 159

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)! date.setDate(3, 8, 59); Therefore, why should I bother to check status? date.setDate(1959, 3, 8); 160

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)! date.setDate(3, 8, 59); Therefore, why should I bother to check status? date.setDate(1959, 3, 8); 161

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

Returning status implies a wide contract.

162

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior:

Returning status implies a wide contract. Wide contracts prevent defending against such errors in any build mode. 163

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; d_day = d; } 164

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; d_day = d; } 165

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; Narrow Contract: d_day = d; Checked Only In } “Debug Mode”

166

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: int Date::setDateIfValid(int y, int m, int d) { if (!isValid(y, m, d)) { return !0; } d_year = y; d_month = m; d_day = d; return 0; } 167

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: int Date::setDateIfValid(int y, int m, int d) { if (!isValid(y, m, d)) { return !0; } Wide Contract: d_year = y; d_month = m; Checked in d_day = d; Every Build Mode return 0; } 168

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? TYPE& vector::operator[](int idx);

169

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? TYPE& vector::at(int idx); 170

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? TYPE& vector::at(int idx); 171

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior! TYPE& vector::at(int idx); 172

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior! TYPE& vector::at(int idx); 173

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior! TYPE& vector::at(int idx); 174

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero?

175

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

176

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be? if (idx < 0) idx = 0; if (idx > length()) idx = length(); 177

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be? if (idx < 0) idx = 0; if (idx > length()) idx = length(); idx = abs(idx) % (length() + 1); 178

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be? if (idx < 0) idx = 0; if (idx > length()) idx = length(); idx = abs(idx) % (length() + 1); 179

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be? if (idx < 0) idx = 0; if (idx > length()) idx = length(); idx = abs(idx) % (length() + 1); 180

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be? if (idx < 0) idx = 0; if (idx > length()) idx = length(); idx = abs(idx) % (length() + 1); 181

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero?

182

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No!

183

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No! assert(0 <= idx); assert(idx <= length()); 184

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts Narrow Contracts Imply Undefined Behavior: Should the behavior for void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No! assert(0 <= idx); assert(idx <= length()); 185

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

186

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts Narrow, but not too narrow.

187

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts Narrow, but not too narrow. Should the behavior for void replace(int index, const TYPE& value, int numElements); be defined when index is length() and numElements is zero? 188

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts ? E.g., length() is 5.

index 5 4 3 2 1 0 0 1

2

3

4

5

numElements

189

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts ? E.g., length() is 5.

index 5 4 3 2 1 0 0 1

2

3

4

5

numElements

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

190

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts X ?

index

E.g., length() is 5.

5 4 3 2 1 0 0 1

2

3

4

5

numElements

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

191

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts index 5

X ?

E.g., length() is 5.

Now a client 4 3 would have 2 to check for this 1 0 special case. 0 1 2 3 4 5 numElements void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

192

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts index 5

X ?

E.g., length() is 5.

Now a client 4 3 would have 2 to check for this 1 0 special case. 0 1 2 3 4 5 numElements void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

193

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts ? E.g., length() is 5.

index

Assuming no extra code is needed to handle it …

5 4 3 2 1 0 0 1

2

3

4

5

numElements

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

194

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts ! E.g., length() is 5.

index

Assuming no extra code is needed to handle it …

5 4 3 2 1 0 0 1

2

3

4

5

… it is naturally more efficient to allow it.

numElements

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

195

3. Narrow versus Wide Contracts (review)

End of Section

Questions? 196

3. Narrow versus Wide Contracts (review)

What Questions are we Answering? • What do we mean by a narrow versus a wide contract? – Should std::strlen(0) be required to do something reasonable? – Should Date::setDate(int, int, int) return a status?

• What should happen when the behavior is undefined? – Should what happens be part of the component-level contract?

• What about the behavior for these specific interfaces:

– Should operator[](int index) check to see if index is less than zero or greater than length()? • And what should happen if index is out of range?

– Should insert(int index, const TYPE& value) be defined when index is greater than length() or less than zero? – Should replace(int index, const TYPE& value, int numElements) be defined when index is length() and numElements is zero?

• What do we mean by Defensive Programming (DP)?

197

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

198

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

199

4. Proper Inheritance

Three Kinds of Inheritance

200

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

201

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

Public, Protected, Private? 202

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

Public, Protected, Private? 203

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

204

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

205

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

• Structural Inheritance: – Non-Virtual Functions

206

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

• Structural Inheritance: – Non-Virtual Functions

• Implementation Inheritance: –Non-Pure Virtual Functions 207

4. Proper Inheritance

Interface Inheritance class TcpChannel : public Channel {

/* … */ public:

TcpChannel

// … (creators) virtual int read(char *buffer, int numBytes) {…} virtual int write(const char *buffer, int numBytes) {…} };

class Channel { public:

Channel

virtual ~Channel() { } virtual int read(char *buffer, int numBytes) = 0; virtual int write(const char *buffer, int numBytes) = 0; }; 208

4. Proper Inheritance

Structural Inheritance Pixel

class Pixel : public Point { public: enum Color { RED, GREEN, BLUE }; private: Color d_color; public: // … (creators) void setColor(Color color) { /* … */ } Color color ( ) const { /* … */ } };

Point

class Point { int d_x; int d_y; public: // … (creators) void setX(int x) { /* … */ } void setY(int y) { /* … */ } int x() const { /* … */ } int y() const { /* … */ } };

209

4. Proper Inheritance

Implementation Inheritance CompositeWidget

Widget

class CompositeWidget : public Widget { // … public: // … (creators) virtual const char *widgetCategory() const { return "COMP"; } virtual int numChildren() const { /* … */ } // … };

class Widget { Point d_origin; // … public: // … (creators) virtual bool isNameable() const { return false; } virtual const char *instanceName() const { return 0; } virtual bool hasLocation() const { return true; } virtual Point origin() const { return d_origin; } virtual const char *widgetCategory() const { return "LEAF"; } virtual int numChildren const { return 0; } // … };

210

4. Proper Inheritance

What Is Proper Inheritance? 2 Derived

Is-A

Implements Extends Is-Substitutable-For 1 Base

211

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship? – What does it mean?

212

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship? – What does it mean?

• Weaker Preconditions? • Stronger Postconditions? • Same Invariants?

213

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship? – What does it mean?

• • • •

Weaker Preconditions? Stronger Postconditions? Same Invariants? Providing a Proper Superset of Behavior?

214

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship? – What does it mean?

• • • • •

Weaker Preconditions? Stronger Postconditions? Same Invariants? Providing a Proper Superset of Behavior? Substitutability? – Of what? – What criteria?

215

4. Proper Inheritance

What Is Proper Inheritance? 2 Derived

Is-A

Implements Extends Is-Substitutable-For 1 Base

216

4. Proper Inheritance

What Is Proper Inheritance? 2 Derived

Is-A

Implements Extends Is-Substitutable-For 1 Base

The Is-A Relation: The implementation of a derived class must satisfy (simultaneously) its own contract, as well as that of “each” base class. 217

4. Proper Inheritance

What Is Proper Inheritance? What about the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 218

4. Proper Inheritance

What Is Proper Inheritance? What about the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 219

4. Proper Inheritance

What Is Proper Inheritance? What about the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 220

4. Proper Inheritance

What Is Proper Inheritance?

Derived f(int, double, const char *)

Base f(int, double, const char *) 221

4. Proper Inheritance

What Is Proper Inheritance?

Derived f(int, double, const char *)

Base f(int, double, const char *) 222

4. Proper Inheritance

What Is Proper Inheritance?

Derived f(int, double, const char *)

Base f(int, double, const char *) 223

4. Proper Inheritance

What Is Proper Inheritance?

Derived f(int, double, const char *)

Base f(int, double, const char *) 224

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived(); Base *bp = dp;

// bp = 0x002140

Derived f(int, double, const char *)

Base f(int, double, const char *) 225

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170: 226

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170: 227

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 228

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 229

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 230

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 231

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 232

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 233

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

bp->f(1, 2.0, “three”);

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 234

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

bp->f(1, 2.0, “three”); dp->f(1, 2.0, “three”);

Derived f(int, double, const char *)

Base f(int, double, const char *)

0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 235

4. Proper Inheritance

What Is Proper Inheritance? Derived *dp = new Derived();

// dp = 0x002140

Base

// bp = 0x002140

*bp = dp;

bp->f(1, 2.0, “three”); dp->f(1, 2.0, “three”);

Derived f(int, double, const char *)

Base f(int, double, const char *)

Identical Behavior 0x002130: 0x002138: 0x002140: 0x002148: 0x002150: 0x002158: 0x002160: 0x002168: 0x002170:

Object of type

Derived 236

4. Proper Inheritance

What Is Proper Inheritance? What about the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 237

4. Proper Inheritance

What Is Proper Inheritance? What about the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 238

4. Proper Inheritance

What Is Proper Inheritance? Derived::f(int x); Derived::g(int x); Derived::h();

Derived

Base Base::f(int x); Base::g(int x);

// Defined for all x. // Defined for all x. // Note: not accessible from Base class.

g(int) f(int) h()

Derived Interface and Contract

g(int) f(int) // Defined for all x. // Defined only for 0 <= x.

Base Interface and Contract 239

4. Proper Inheritance

What Is Proper Inheritance? Derived::f(int x); Derived::g(int x); Derived::h();

Derived

Base Base::f(int x); Base::g(int x);

// Defined for all x. // Defined for all x. // Note: not accessible from Base class.

g(int) f(int) h()

Derived Interface and Contract

g(int) f(int) // Defined for all x. // Defined only for 0 <= x.

Base Interface and Contract 240

4. Proper Inheritance

What Is Proper Inheritance? Derived::f(int x); Derived::g(int x); Derived::h();

Derived

Base Base::f(int x); Base::g(int x);

// Defined for all x. // Defined for all x. // Note: not accessible from Base class.

g(int) f(int) h()

Derived Interface and Contract

g(int) f(int) // Defined for all x. // Defined only for 0 <= x.

Base Interface and Contract 241

4. Proper Inheritance

What Is Proper Inheritance? Derived::f(int x); Derived::g(int x); Derived::h();

Derived

Base Base::f(int x); Base::g(int x);

// Defined for all x. // Defined for all x. // Note: not accessible from Base class.

g(int) f(int) h()

Derived Interface and Contract

g(int) f(int) // Defined for all x. // Defined only for 0 <= x.

Base Interface and Contract 242

4. Proper Inheritance

Pure Interface Inheritance Constructors

D::f

Implementation

Derived

B::f

Interface

Base

For each function D::f in the derived class overriding a virtual one B::f in the base class, the (documented) preconditions of D::f must be no stronger than those for B::f, and the postconditions no weaker. 243

4. Proper Inheritance

Pure Interface Inheritance Constructors

D::f

Implementation

Derived Implements the Interface B::f

Interface

Base

For each function D::f in the derived class overriding a virtual one B::f in the base class, the (documented) preconditions of D::f must be no stronger than those for B::f, and the postconditions no weaker. 244

4. Proper Inheritance

Pure Interface Inheritance Constructors

D::f

Implementation

Derived Implements the Interface B::f

Interface

Base

For each function D::f in the derived class overriding a virtual one B::f in the base class, the (documented) preconditions of D::f must be no stronger than those for B::f, and the postconditions no weaker. 245

4. Proper Inheritance

Pure Interface Inheritance Constructors

D::f

Implementation

Derived Implements the Interface B::f

Interface

Base

For each function D::f in the derived class overriding a virtual one B::f in the base class, the (documented) are typically the same as preconditions of D::f must be no stronger than those for B::f, and the postconditions no weaker. 246

4. Proper Inheritance

Pure Interface Inheritance

B::f

Channel

247

4. Proper Inheritance

Pure Interface Inheritance

B::f

Channel

virtual int write(const char *buffer, int numBytes) = 0; // Write the specified 'numBytes' from the specified // 'buffer'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless // '0 <= numBytes <= 32767'.

248

4. Proper Inheritance

Pure Interface Inheritance D::f

TcpChannel

B::f

Channel

virtual int write(const char *buffer, int numBytes) = 0; // Write the specified 'numBytes' from the specified // 'buffer'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless // '0 <= numBytes <= 32767'.

249

4. Proper Inheritance

Pure Interface Inheritance D::f

TcpChannel

B::f

Channel

virtual int write(const char *buffer, int numBytes); // Write to this TCP/IP channel the specified // 'numBytes' from the specified 'buffer'. Return 0 on // success, and a non-zero value otherwise. The // behavior is undefined unless '0 == numBytes % 4'.

virtual int write(const char *buffer, int numBytes) = 0; // Write the specified 'numBytes' from the specified // 'buffer'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless // '0 <= numBytes <= 32767'.

250

4. Proper Inheritance

Pure Interface Inheritance D::f

TcpChannel

B::f

Channel

virtual int write(const char *buffer, int numBytes); // Write to this TCP/IP channel the specified // 'numBytes' from the specified 'buffer'. Return 0 on // success, 1 if '0 != numBytes % 4', and a negative // value otherwise.

virtual int write(const char *buffer, int numBytes) = 0; // Write the specified 'numBytes' from the specified // 'buffer'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless // '0 <= numBytes <= 32767'.

251

4. Proper Inheritance

Pure Interface Inheritance D::f

TcpChannel

B::f

Channel

virtual int write(const char *buffer, int numBytes); // Write to this TCP/IP channel the specified // 'numBytes' from the specified 'buffer'. Return 0 on // success, and a non-zero value otherwise. Note that // this functionality is not yet implemented on Windows; // on that platform, this function always returns -1.

virtual int write(const char *buffer, int numBytes) = 0; // Write the specified 'numBytes' from the specified // 'buffer'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless // '0 <= numBytes <= 32767'.

252

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

253

4. Proper Inheritance

What Is a Proper Subtype/Subclass? “A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra.” – Barbara Liskov .

(OOPSLA ’87)

254

4. Proper Inheritance

What Is a Proper Subtype/Subclass? “A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra.” – Barbara Liskov .

(OOPSLA ’87)

Can

create it. TcpChannel

Channel

Interface Inheritance

255

4. Proper Inheritance

What Is a Proper Subtype/Subclass? “A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra.” – Barbara Liskov .

(OOPSLA ’87)

Can

create it.

Can do something

more with it.

TcpChannel

Pixel

Channel

Point

Interface

Structural

Inheritance

Inheritance

256

4. Proper Inheritance

What Is a Proper Subtype/Subclass? “A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra.” – Barbara Liskov .

(OOPSLA ’87)

Can

create it.

Can do something

Can create something

more with it.

else with it. CompositeWidget

TcpChannel

Pixel

Widget

Channel

Point

Interface

Structural

Implementation

Inheritance

Inheritance

Inheritance

257

4. Proper Inheritance

What Is Liskov Substitution?

258

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)?

259

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place?

260

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place? • (How?) Does LSP relate to inheritance in C++?

261

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place? • (How?) Does LSP relate to inheritance in C++? • After Liskov substitution is applied, can (observable) behavior be (subtly) different?

262

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place? • (How?) Does LSP relate to inheritance in C++? • After Liskov substitution is applied, can (observable) behavior be (subtly) different? • Does LSP apply to all three kinds of inheritance?

263

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place? • (How?) Does LSP relate to inheritance in C++? • After Liskov substitution is applied, can (observable) behavior be (subtly) different? • Does LSP apply to all three kinds of inheritance? • Does LSP have any other practical applications? 264

4. Proper Inheritance

What Is Liskov Substitution? What exactly is the Liskov Substitution Principle (LSP)? • What motivated LSP in the first place? • (How?) Does LSP relate to inheritance in C++? • After Liskov substitution is applied, can (observable) behavior be (subtly) different? • Does LSP apply to all three kinds of inheritance? • Does LSP have any other practical applications? • Let’s have a look… 265

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

266

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

267

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 268

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 269

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 270

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 271

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 272

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

Note order is different!

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 273

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 274

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

Note order is different!

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 275

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

276

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

277

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) If, for each “derived-class” object o1 of type S, there exists a “base-class” object o2 of type T such that, for all programs P defined in terms of type T, the behavior of P is unchanged when the “derived-class” object o1 is substituted for the “base-class” object o2, then S is a subtype of T.

278

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) If, for each “derived-class” object o1 of type S, there exists a “base-class” object o2 of type T such that, for all programs P defined in terms of type T, the behavior of P is unchanged when the “derived-class” object o1 is substituted for the “base-class” object o2, then S is a subtype of T. If, for each “derived-class” object d of type D, there exists a “base-class” object b of type B such that, for all programs P defined in terms of type B, the behavior of P is unchanged when the “derived-class” object d is substituted for the “base-class” object b, then D is a subtype of B.

279

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) If, for each “derived-class” object o1 of type S, there exists a “base-class” object o2 of type T such that, for all programs P defined in terms of type T, the behavior of P is unchanged when the “derived-class” object o1 is substituted for the “base-class” object o2, then S is a subtype of T. If, for each “derived-class” object d of type D, there exists a “base-class” object b of type B such that, for all programs P defined in terms of type B, the behavior of P is unchanged when the “derived-class” object d is substituted for the “base-class” object b, then D is a subtype of B. If, for each object d of type D, there exists an object b of type B such that, for all programs P defined in terms of B, the behavior of P is unchanged when d is substituted for b, then D is a subtype of B. 280

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87) If, for each “derived-class” object o1 of type S, there exists a “base-class” object o2 of type T such that, for all programs P defined in terms of type T, the behavior of P is unchanged when the “derived-class” object o1 is substituted for the “base-class” object o2, then S is a subtype of T. If, for each “derived-class” object d of type D, there exists a “base-class” object b of type B such that, for all programs P defined in terms of type B, the behavior of P is unchanged when the “derived-class” object d is substituted for the “base-class” object b, then D is a subtype of B. If, for each object d of type D, there exists an object b of type B such that, for all programs P defined in terms of B, the behavior of P is unchanged when d is substituted for b, then D is a subtype of B. 281

4. Proper Inheritance

What Is Liskov Substitution? If, for each object d of type D, there exists an object b of type B such that, for all programs P defined in terms of B, the behavior of P is unchanged when d is substituted for b, then D is a subtype of B. class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 282

4. Proper Inheritance

What Is Liskov Substitution? If, for each object d of type D, there exists an object b of type B such that, for all programs P defined in terms of B, the behavior of P is unchanged when d is substituted for b, then D is a subtype of B. class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 283

4. Proper Inheritance

What Is Liskov Substitution? If, for each object d of type D, there exists an object b of type B such that, for all programs P defined in terms of B, the behavior of P is unchanged when d is substituted for b, then D is a subtype of B. class Bool { bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool { public: }; Fool(int x) : Bool(!x) { }

void p(const Bool& x, const Bool& y, …) { /* … */ } main() { Bool b0(false); Bool b1(true); // … p(b0, b1, …); }

main() { Fool f0(false); Fool f1(true); // … p(f1, f0, …); } 284

4. Proper Inheritance

What Is Proper Inheritance? Recall the following general property: For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that baseclass pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave! 285

4. Proper Inheritance

What Is Proper Inheritance? void example(Derived *pDerived) { Base *pBase = pDerived; #ifdef USE_DERIVED_CLASS_INTERFACE pDerived->someMethod(/* … */);

Derived

int result = someFunction(*pDerive); #else pBase->someMethod(/* … */);

Base

int result = someFunction(*pBase);

#endif 286

4. Proper Inheritance

Pure Structural Inheritance #ifdef USE_BASE_CLASS_INTERFACE typedef Point Type; #else typedef Pixel Type; #endif void anyProgram(Type *p);

Pixel

Point

void main() { Pixel pixel(1, 2, Pixel::BLUE); anyProgram(&pixel); } using std::cout; // (We do this only using std::endl; // in test drivers.) 287

4. Proper Inheritance

Pure Structural Inheritance void anyProgram(Type *p) { cout << p->x() << endl; }

Pixel

Point

int Point::x() const { return d_x; } 288

4. Proper Inheritance

Pure Structural Inheritance void anyProgram(Type *p) { p->setY(10); }

Pixel

Point

void Point::setY(int y) { d_y = y; } 289

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

Pixel

void anyProgram(Type *p) { cout << p->color() << endl; }

Pixel::Color Pixel::color() const { return d_color; }

Point

290

4. Proper Inheritance

Pure Structural Inheritance void anyProgram(Type *p) { p->setY(10); }

Pixel

void Pixel::setY(int y) { cout << "Pixel::setY(int y)" << endl; d_y = y; }

Point

void Point::setY(int y) { d_y = y; } 291

4. Proper Inheritance

Pure Structural Inheritance void anyProgram(Type *p) { p->setY(10); }

Pixel

void Pixel::setY(int y) { cout << "Pixel::setY(int y)" << endl; d_y = y; }

Point

void Point::setY(int y) { d_y = y; }

!

292

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … static int s_numSetY; public: // … };

void anyProgram(Type *p) { p->setY(10); }

Pixel

void Pixel::setY(int y) { ++s_numSetY; // Pixel class data d_y = y; }

Point

void Point::setY(int y) { d_y = y; } 293

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … static int s_numSetY; public: // … };

Pixel

Point

void anyProgram(Type *p) { p->setY(10); cout << p->numSetY() << endl; }

void Pixel::setY(int y) { ++s_numSetY; // Pixel class data d_y = y; } int Pixel::numSetY() { return s_numSetY; } void Point::setY(int y) { d_y = y; } 294

4. Proper Inheritance

Pure Structural Inheritance void anyProgram(Type *p) { p->setY(10); }

Pixel

Point

void Pixel::setY(int y) // Set the y-coordinate of this object to the absolute value of the // specified 'y'. The behavior is undefined unless 'INT_MIN < y'. { d_y = y < 0 ? -y : y; } void Point::setY(int y) // Set the y-coordinate of this object to the specified 'y'. // The behavior is undefined unless '0 <= y'. { d_y = y; }

295

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 296

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > sizeof(Point)) ? cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 297

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > 8) // sizeof(Point) cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 298

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > 8) // sizeof(Point) cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 299

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > 8) // sizeof(Point) cout << "It's not a point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 300

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; } 301

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof p->self() > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

const Pixel& Pixel::self() const { return *this; }

Point

const Point& Point::self() const { return *this; }

!

302

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

void anyProgram(Type *p) { if (sizeof *p > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

Point

303

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

!

void anyProgram(Type *p) { if (sizeof *p > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

Point

304

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

!

void anyProgram(Type *p) { if (sizeof *p > sizeof(Point)) cout << "It's not a Point!" << endl; }

Pixel

Point

305

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

!

Pixel

Point

void anyProgram(Type *p) { if (sizeof *p > sizeof(Point)) cout << "It's not a Point!" << endl; }

Proper Structural Inheritance extends functionality, but does not extend the object’s footprint.

306

4. Proper Inheritance

Pure Structural Inheritance class Pixel : public Point { // … Color d_color; // … };

!

Pixel

void anyProgram(Type *p) { double alignmentHack; // Don’t do it! char buffer[sizeof(Point)]; (Type *)&buffer = *p; } ?!?!

buffer

Point buffer

The same “size” issue applies to arrays of objects! 307

4. Proper Inheritance

Implementation Inheritance CompositeWidget

Implementation hierarchies are highly problematic! Incorporating implementation with interface inheritance:

Widget

– Makes software brittle, inflexible, and hard to maintain. – Exposes public clients to physical (compileand link-time) dependencies on the shared implementation. – Adds nothing that cannot be done with pure interface inheritance and layering.

Its only value is as a syntactic expedient! 308

4. Proper Inheritance

Using Interface Inheritance Effectively Point

Shape

Polygon

Square

Rectangle

MyRectangle

309

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

310

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

origin

Polygon

Square

A Rectangle Is-A Square with a length attribute? origin; width

? Rectangle

origin; width; length

MyRectangle

311

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

origin

Polygon

Square

A Rectangle Is-A Square with a length attribute? origin; width

? Rectangle

MyRectangle

origin; width; length

Rectangle does not respect Square Invariant

312

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

origin

Polygon

Square

A Rectangle Is-A Square with a length attribute? origin; width

? Rectangle

origin; width; length

MyRectangle

313

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

314

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

315

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

316

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

317

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

318

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 319

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 320

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 321

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 322

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 323

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 324

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 325

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

Either Assert or No Longer Square

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 326

4. Proper Inheritance

Using Interface Inheritance Effectively Square

Rectangle

Either Assert or No Longer Square

void stretchBy1(Rectangle *r) { int wid = r->width(); int len = r->length(); r->setLength(len + 1); assert(wid == r->width()); assert(len + 1 == r->length()); } 327

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

328

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

329

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

330

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

331

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

332

4. Proper Inheritance

Using Interface Inheritance Effectively Point

x; y

Shape origin; numVertices; operator[](int index)

Polygon

origin

Square

Rectangle

origin; width

origin; width; length

MyRectangle

333

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 334

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 335

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 336

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 337

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 338

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 339

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 340

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 341

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 342

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 343

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 344

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 345

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 346

4. Proper Inheritance

Using Interface Inheritance Effectively TheirPolygon()

YourSquare()

MyRectangle()

(Concrete)

(Concrete)

(Concrete)

TheirPolygon

YourSquare

MyRectangle

void setSide(int side)

(Modifiable)

Square ConstSquare void setWidth(int width) void setLength(int length)

int side() const (Modifiable)

Rectangle void appendVertex(const Point& v) void removeVertex(int i) (Modifiable)

ConstRectangle int width() const int length() const

Polygon ConstPolygon void setOrigin(const Point& v);

Point vertex(int i) const int numVertices() const

(Modifiable)

Shape ConstShape origin() const; 347

4. Proper Inheritance

Using Interface Inheritance Effectively

The principal clients of Interface Inheritance are both the PUBLIC CLIENT and the DERIVED-CLASS AUTHOR. 348

4. Proper Inheritance

Using Interface Inheritance Effectively

Channel int write(const char *b, int n); int read(char *b, int n); 349

4. Proper Inheritance

Using Interface Inheritance Effectively

MyChannel Channel int write(const char *b, int n); int read(char *b, int n); 350

4. Proper Inheritance

Using Interface Inheritance Effectively

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n); 351

4. Proper Inheritance

Using Interface Inheritance Effectively

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n); 352

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n); 353

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n); 354

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

355

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter

MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

356

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter Client3 MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

357

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter Client3 MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

3rd Party Product B 358

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

PbTimedChannelAdapter

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter Client3 MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

3rd Party Product B 359

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client4

PbTimedChannelAdapter

Client2

TimedChannel int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter Client3 MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

3rd Party Product B 360

4. Proper Inheritance

Using Interface Inheritance Effectively YourTimedChannel

Client4

PbTimedChannelAdapter

Client2

TimedChannel Client5

int write(const char *b, int n, int t); int read(char *b, int n, int t);

PaChannelAdapter Client3 MyChannel

Client1

Channel int write(const char *b, int n); int read(char *b, int n);

3rd Party Product A

3rd Party Product B 361

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

362

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef elem() ;

template class ConstElemRef { const TYPE *d_elem_p; friend class ElemRef; //

Note friendship

private: // Not Implemented. TBD ConstElemRef& operator=(Const ConstElemRef&); public: // CREATORS ConstElemRef(const TYPE *elem); ConstElemRef(const ConstElemRef& ref); ~ConstElemRef(); // ACCESSORS const TYPE& elem() const; }; 363

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef elem() ;

template class ConstElemRef { const TYPE *d_elem_p; friend class ElemRef; //

Single Pointer Data Member Note friendship

private: // Not Implemented. TBD ConstElemRef& operator=(Const ConstElemRef&); public: // CREATORS ConstElemRef(const TYPE *elem); ConstElemRef(const ConstElemRef& ref); ~ConstElemRef(); // ACCESSORS const TYPE& elem() const; }; 364

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef elem() ;

template class ConstElemRef { const TYPE *d_elem_p; friend class ElemRef; //

Derived Class Declared Friend Note friendship

private: // Not Implemented. TBD ConstElemRef& operator=(Const ConstElemRef&); public: // CREATORS ConstElemRef(const TYPE *elem); ConstElemRef(const ConstElemRef& ref); ~ConstElemRef(); // ACCESSORS const TYPE& elem() const; }; 365

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef elem() ;

template class ConstElemRef { const TYPE *d_elem_p; friend class ElemRef; //

Copy Assignment Not Implemented Note friendship

private: // Not Implemented. TBD ConstElemRef& operator=(Const ConstElemRef&); public: // CREATORS ConstElemRef(const TYPE *elem); ConstElemRef(const ConstElemRef& ref); ~ConstElemRef(); // ACCESSORS const TYPE& elem() const; }; 366

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef elem() ;

template class ConstElemRef { const TYPE *d_elem_p; friend class ElemRef; //

Note friendship

private: // Not Implemented. TBD ConstElemRef& operator=(Const ConstElemRef&); public: // CREATORS ConstElemRef(const TYPE *elem); ConstElemRef(const ConstElemRef& ref); ~ConstElemRef();

Read-Only Access

// ACCESSORS const TYPE& elem() const; }; 367

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

template class ElemRef : public ConstElemRef { public: // CREATORS ElemRef(TYPE *elem); ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const; };

368

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

Public Structural Inheritance

template class ElemRef : public ConstElemRef { public: // CREATORS ElemRef(TYPE *elem); ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const; };

369

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

No Additional Member Data

template class ElemRef : public ConstElemRef { public: // CREATORS ElemRef(TYPE *elem); ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const; };

370

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

Copy Assignment Implemented

template class ElemRef : public ConstElemRef { public: // CREATORS ElemRef(TYPE *elem); ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const; };

371

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

template class ElemRef : public ConstElemRef { public: // CREATORS ElemRef(TYPE *elem); ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const;

Read-Write Access };

372

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

An ElemRef template Is-A class ElemRef : public ConstElemRef { ConstElemRef public: // CREATORS with ElemRef(TYPE *elem); “Write ElemRef(const ElemRef& ref); Access” ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const;

Read-Write Access };

373

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRef elem() ;

class ConstElemRef { const TYPE *d_elem_p; // … const TYPE& elem() const; };

(Modifiable)

ElemRef elem() ;

An std::iterator template Is-A class ElemRef : public ConstElemRef { std::const_iterator public: // CREATORS with ElemRef(TYPE *elem); “Write Access” ElemRef(const ElemRef& ref); ~ElemRef(); // MANIPULATORS ElemRef& operator=(const ElemRef&); // Fine. TBD // ACCESSORS TYPE& elem() const;

Read-Write Access };

374

4. Proper Inheritance

Using Structural Inheritance Effectively (Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

const TYPE& ConstElemRef::elem() const { return *d_elem_p; }

TYPE& ElemRef::elem() const { return *const_cast(d_elem_p); } // Note use of friendship as well.

Note: same component due to friendship. 375

4. Proper Inheritance

Using Structural Inheritance Effectively Note we are casting-away const TYPE& ConstElemRef::elem() const const (Non-Modifiable)

{ return *d_elem_p;

ConstElemRef

}

(Modifiable)

ElemRef

TYPE& ElemRef::elem() const { return *const_cast(d_elem_p); } // Note use of friendship as well.

Note: same component due to friendship. 376

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

377

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

378

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

379

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

380

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

381

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

382

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

383

4. Proper Inheritance

Using Structural Inheritance Effectively Be especially careful to ensure const-correctness when const-casting is involved.

void g(ConstElemRef *cer1, const ConstElemRef& cer2) { *cer1 = cer2; // Enable const-correctness violation due to slicing. } // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

template < class TYPE> void f(const TYPE& constElem) { TYPE dummy; ElemRef er(&dummy); ConstElemRef cer(&constElem);

(Modifiable)

ElemRef

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'. er.elem() = TYPE(); // Clobber 'constElem'.

384

4. Proper Inheritance

Using Structural Inheritance Effectively

The principal client of Structural Inheritance is the PUBLIC CLIENT.

385

4. Proper Inheritance

Using Structural Inheritance Effectively ConstElemRefClient

(Non-Modifiable)

ConstElemRef ElemRefClient

(Modifiable)

ElemRef

Note: No Runtime-Performance Overhead (e.g., due to Dynamic Binding). 386

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidget

WidgetClient

Widget instanceName origin move draw numChildren addChild removeChild

387

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient CompositeWidget numChildren addChild removeChild

WidgetClient Widget instanceName origin move draw

388

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient CompositeWidget numChildren addChild removeChild

WidgetClient

MyWidget Widget instanceName origin move draw

389

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient CompositeWidget numChildren addChild removeChild

WidgetClient

MyWidget WidgetImp

Widget

instanceName origin move draw

390

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient CompositeWidget numChildren addChild removeChild

WidgetClient

MyWidget WidgetImp

YourWidget Widget

instanceName origin move draw

391

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidget numChildren addChild removeChild

WidgetClient

MyWidget WidgetImp

YourWidget Widget

instanceName origin move draw

392

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

393

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

394

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

395

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

396

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

397

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

398

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

399

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

400

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

Widen interface first;

YourWidget Widget

instanceName origin move draw

401

4. Proper Inheritance

Using Implementation Inheritance Effectively CompositeWidgetClient

MyCompositeWidget CompositeWidgetImp YourCompositeWidget CompositeWidget numChildren addChild removeChild

MyWidget

WidgetClient

WidgetImp

YourWidget Widget

instanceName origin move draw

Widen interface first; then provide implementation without widening. 402

4. Proper Inheritance

Using Implementation Inheritance Effectively

The principal client of Implementation Inheritance is the DERIVED-CLASS AUTHOR.

403

4. Proper Inheritance

Using Implementation Inheritance Effectively

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

404

4. Proper Inheritance

Using Implementation Inheritance Effectively

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

405

4. Proper Inheritance

Using Implementation Inheritance Effectively

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

406

4. Proper Inheritance

Using Implementation Inheritance Effectively

WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

407

4. Proper Inheritance

Using Implementation Inheritance Effectively

CompositeWidgetPartialImp WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

408

4. Proper Inheritance

Using Implementation Inheritance Effectively

MyWidget CompositeWidgetPartialImp WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

409

4. Proper Inheritance

Using Implementation Inheritance Effectively MyCompositeWidget MyWidget CompositeWidgetPartialImp WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

410

4. Proper Inheritance

Using Implementation Inheritance Effectively YourWidget

MyCompositeWidget

MyWidget CompositeWidgetPartialImp WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

411

4. Proper Inheritance

Using Implementation Inheritance Effectively YourCompositeWidget YourWidget

MyCompositeWidget

MyWidget CompositeWidgetPartialImp WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

412

4. Proper Inheritance

Using Implementation Inheritance Effectively YourCompositeWidget YourWidget MyWidget

MyCompositeWidget

TheirCompositeWidget CompositeWidgetPartialImp

WidgetPartialImp

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

413

4. Proper Inheritance

Using Implementation Inheritance Effectively YourCompositeWidget YourWidget MyWidget

MyCompositeWidget

TheirCompositeWidget CompositeWidgetPartialImp

WidgetPartialImp

TheirWidget

CompositeWidget numChildren addChild removeChild

Widget instanceName origin move draw

Part of Framework using CompositeWidget

Part of Framework using Widget Framework

414

4. Proper Inheritance

Combining Kinds of Inheritance

415

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

416

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface –Typically for Efficiency and Syntactic Sugar.

417

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface –Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation

418

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface –Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then implementation inheritance (no widening) .

419

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface –Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then implementation inheritance (no widening) .

• Implementation & Structural

420

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface –Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then implementation inheritance (no widening) .

• Implementation & Structural –Bad Idea: Unnecessarily addresses the needs of derived class authors and public clients in the same physical component. 421

4. Proper Inheritance

Combining Kinds of Inheritance virtual void g();

virtual void g() { } virtual void h() { }

Public Client

inline int f(); virtual void g() = 0; virtual void h() = 0;

422

4. Proper Inheritance

Combining Kinds of Inheritance virtual void g();

Public Client

inline int f(); virtual void g(); virtual void h();

423

4. Proper Inheritance

Combining Kinds of Inheritance virtual void g();

Public Client

inline int f(); virtual void g(); virtual void h();

424

4. Proper Inheritance

Combining Kinds of Inheritance virtual void g();

Public Client

inline int f(); virtual void g(); virtual void h();

425

4. Proper Inheritance

Relative Utility Interface Inheritance

Structural Inheritance Implementation Inheritance 426

4. Proper Inheritance

Physical Substitutability

427

4. Proper Inheritance

Physical Substitutability

428

4. Proper Inheritance

Physical Substitutability

429

4. Proper Inheritance

Physical Substitutability What Criteria Must Be Satisfied?

430

4. Proper Inheritance

Physical Substitutability The new component’s logical behavior:

431

4. Proper Inheritance

Physical Substitutability The new component’s logical behavior: • Preconditions needed for defined behavior can be made weaker, but no stronger.

432

4. Proper Inheritance

Physical Substitutability The new component’s logical behavior: • Preconditions needed for defined behavior can be made weaker, but no stronger. • Pre-existing essential behavior of the component must remain unchanged.

433

4. Proper Inheritance

Physical Substitutability The new component’s logical behavior: • Preconditions needed for defined behavior can be made weaker, but no stronger. • Pre-existing essential behavior of the component must remain unchanged. • New behaviors may be defined, and essential ones extended, so long as the component is backward compatible with pre-existing clients. 434

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics:

435

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much).

436

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much). • Compile-time cannot increase substantially.

437

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much). • Compile-time cannot increase substantially. • Size (footprint) cannot increase (much).

438

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much). • Compile-time cannot increase substantially. • Size (footprint) cannot increase (much). • Dynamic memory usage can’t increase (much).

439

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much). • Compile-time cannot increase substantially. • Size (footprint) cannot increase (much). • Dynamic memory usage can’t increase (much). • Can’t introduce dynamic memory allocation.

440

4. Proper Inheritance

Physical Substitutability The new component’s physical characteristics: • Physical dependencies cannot increase (much). • Compile-time cannot increase substantially. • Size (footprint) cannot increase (much). • Dynamic memory usage can’t increase (much). • Can’t introduce dynamic memory allocation. • Runtime must not be increased significantly for important (relevant) use-cases. 441

4. Proper Inheritance

End of Section

Questions? 442

4. Proper Inheritance

What Questions are we Answering? • What distinguishes Interface, Structural, and Implementation inheritance? • What do we mean by the Is-A relationship, & how does proper inheritance vary from one form to the next. – What does LSP (Liskov Substitution Principle) have to do with it?

• How are each of the three inheritances used effectively? – – – –

Who is the principal client of each kind of inheritance? How are interface and implementation inheritance ordered? Does it make sense to combine two (or all three) inheritances? What is the relative utility of the three forms of inheritance?

• How are structural inheritance, (logical) substitutability, & backward compatibility of (physical) components related? 443

Outline 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

444

Conclusion 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

445

Conclusion 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design.

446

Conclusion 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design. • Logical relationships, such as Is-A and Uses between classes, imply physical dependencies among the components that defined them. 447

Conclusion 1. Components (review) Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design. • Logical relationships, such as Is-A and Uses between classes, imply physical dependencies among the components that defined them. • No cyclic dependencies/long-distance friendships! 448

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

449

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic.

450

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

451

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions. • Undefined Behavior if a precondition isn’t met.

452

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• • • •

An interface is syntactic; a contract is semantic. A contract defines both pre- & postconditions. Undefined Behavior if a precondition isn’t met. What undefined behavior does is undefined!

453

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• • • • •

An interface is syntactic; a contract is semantic. A contract defines both pre- & postconditions. Undefined Behavior if a precondition isn’t met. What undefined behavior does is undefined! Documented essential behavior must not change!

454

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• • • • • •

An interface is syntactic; a contract is semantic. A contract defines both pre- & postconditions. Undefined Behavior if a precondition isn’t met. What undefined behavior does is undefined! Documented essential behavior must not change! Test drivers must verify all essential behavior. 455

Conclusion 2. Interfaces and Contracts (review) Syntax versus Semantics & Essential Behavior

• • • • • • •

An interface is syntactic; a contract is semantic. A contract defines both pre- & postconditions. Undefined Behavior if a precondition isn’t met. What undefined behavior does is undefined! Documented essential behavior must not change! Test drivers must verify all essential behavior. Assertions in destructors help verify invariants. 456

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

457

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

458

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD:

459

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD: – Reduce costs associated with development/testing

460

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD: – Reduce costs associated with development/testing – Improve performance and reduces object-code size

461

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD: – Reduce costs associated with development/testing – Improve performance and reduces object-code size – Allow useful behavior to be added as needed

462

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD: – – – –

Reduce costs associated with development/testing Improve performance and reduces object-code size Allow useful behavior to be added as needed Enable practical/effective Defensive Programming 463

Conclusion 3. Narrow versus Wide Contracts (review) The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior. • Appropriately narrow contracts are GOOD: – – – –

Reduce costs associated with development/testing Improve performance and reduces object-code size Allow useful behavior to be added as needed Enable practical/effective Defensive Programming

• Defensive programming means fault intolerance! 464

Conclusion 4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

465

Conclusion 4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts.

466

Conclusion 4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts. • The static type of the pointer/reference should make no difference in programmatic behavior.

467

Conclusion 4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts. • The static type of the pointer/reference should make no difference in programmatic behavior. • Interface inheritance is (virtually :-) all we need!

468

Conclusion 4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts. • The static type of the pointer/reference should make no difference in programmatic behavior. • Interface inheritance is (virtually :-) all we need! • Backward compatibility for components is a whole lot like proper structural inheritance. 469

Conclusion

The End 470

proper inheritance - GitHub

All essential behavior of our software must be documented, and yet there are important advantages, with respect to development, verification and testing,.

5MB Sizes 3 Downloads 253 Views

Recommend Documents

Lamarckian Inheritance
sometimes known as 'soft' heredity). The Lamarckian theory is thus rejected ... habit-directed form of evolu- tion than with Darwinian 'trial and error'. There were.

Java-Inheritance, Interface & Exception
There is a special way to call the superclass's constructor. – There is ... BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);. Box plainbox = new Box();.

Java-Inheritance, Interface & Exception
System.out.println(k);. } void sum() {. System.out.println(i+j+k);. } } class SimpleInheritance { public static void main(String args[]) {. A superOb = new A();. B subOb ...

Proper Noun Patty.pdf
around! Page 1 of 1. Proper Noun Patty.pdf. Proper Noun Patty.pdf. Open. Extract. Open with. Sign In. Main menu. Displaying Proper Noun Patty.pdf.

manhattan proper brunch.pdf
Page 1 of 2. Eggs & Things. Fiesta Omelet. 3 egg omelet/ bell pepper/ red onion/ cilantro/ pepper jack cheese/ spicy guacamole/ side of breakfast. potatoes. Chocolate Pancake Stack. buttermilk pancakes/ chocolate chips/ maple syrup/ powdered sugar. S

Mixin-based Inheritance - Semantic Scholar
Department of Computer Science ... enforces a degree of behavioral consistency between a ... reference, within the object instance being defined. The.

Inheritance and Polymorphism.pdf
There was a problem previewing this document. Retrying... Download. Connect more apps... Try one of the apps below to open or edit this item. Inheritance and ...

THE STABILIZATION THEOREM FOR PROPER ...
Date: August, 2009. Key words and phrases. groupoids, stabilization, G-Hilbert modules, G-Hilbert ... any Hilbert (H, C0(Y ))-module P, there is an equivariant isomorphism of. Hilbert (H, C0(Y ))- ...... 〈bi,bi〉 converges in C0(Y ). By (3) and (4

Proper Orthogonal Decomposition Model Order ...
Reduction (MOR) is a means to speed up simulation of large systems. Ex- isting MOR techniques mostly apply to linear problems and even then they have to be ...

Man's Supreme Inheritance by F.M.Alexander.pdf
5 JOHNSON'S COURT, E.C.4. LONDON. Page 3 of 239. Man's Supreme Inheritance by F.M.Alexander.pdf. Man's Supreme Inheritance by F.M.Alexander.pdf.

The-Inheritance-The-Innkeepers.pdf
eBook PDF The Inheritance (The Innkeepers). (-eBooks-) The Inheritance (The .... Download John Davies ebook file totally free and this. book pdf identified at ...

PRINCIPLES OF INHERITANCE AND VARIATION.pdf
Mendel was an Austrian Monk who is considered as the “father of genetics “ ... The seeds produced as a result of this cross are collected and grew. ... Eg . tall , dwarf , red flower , violet flower , round seed , wrinkled seed, axial flower ,. t

Mulhall, Book Review, Inheritance and Originality, Wittgenstein ...
Mulhall, Book Review, Inheritance and Originality, Wittgenstein, Heidegger, Kierkegaard.pdf. Mulhall, Book Review, Inheritance and Originality, Wittgenstein, ...

JUDGEMENT ON RIGHTS OF INHERITANCE AND SUCCESSION ...
Main menu. Displaying JUDGEMENT ON RIGHTS OF INHERITANCE AND SUCCESSION OF CHRISTIAN PRIESTS AND NUNS BY KERALA HIGH COURT.pdf.

EMBEDDING PROPER ULTRAMETRIC SPACES INTO ...
Mar 8, 2012 - above. Put Nk := #Pk. We consider each coordinate of an element of ℓNk p is indexed by. (i1,··· ,ik). We define a map fk : {xi1···ik }i1,··· ,ik → ℓNk.