LSP Stphane Ducasse Stephane Ducasseunivsavoie fr http www

  • Slides: 15
Download presentation
LSP Stéphane Ducasse Stephane. Ducasse@univ-savoie. fr http: //www. listic. univ-savoie. fr/~ducasse/ Stéphane Ducasse ---

LSP Stéphane Ducasse Stephane. [email protected] fr http: //www. listic. univ-savoie. fr/~ducasse/ Stéphane Ducasse --- 2005 S. Ducasse 1

License: CC-Attribution-Share. Alike 2. 0 http: //creativecommons. org/licenses/by-sa/2. 0/ S. Ducasse 2

License: CC-Attribution-Share. Alike 2. 0 http: //creativecommons. org/licenses/by-sa/2. 0/ S. Ducasse 2

A step deeper in Subtyping. . . S. Ducasse 3

A step deeper in Subtyping. . . S. Ducasse 3

Liskov Substitution Principle (LSP) if for each object o 1 of type S there

Liskov Substitution Principle (LSP) if for each object o 1 of type S there is another object o 2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o 1 is substituted for o 2, then S is a subtype of T. Barbara Liskov, "Data Abstraction and Hierarchy, " SIGPLAN Notices, 23, 5 (May 1988) S. Ducasse 4

A Simple Bag We will define a Bag as an object that accepts two

A Simple Bag We will define a Bag as an object that accepts two messages: put and count (send a-Bag 'put x) puts an element x into the Bag, and (send a-Bag 'count x) gives the count of occurrences of x in the Bag (without changing a-Bag's state). S. Ducasse 5

A Simple Set Likewise, a Set is defined as an object that accepts two

A Simple Set Likewise, a Set is defined as an object that accepts two messages: (send a-Set 'put x) puts an element x into a-Set unless it was already there, (send a-Set 'count x) gives the count of occurrences of x in a-Set (which is always either 0 or 1). S. Ducasse 6

A Bag Function (define (fnb bag) (send bag 'put 5) (send bag 'count 5))

A Bag Function (define (fnb bag) (send bag 'put 5) (send bag 'count 5)) The behavior of this function can be summed as follows: given a Bag, the function adds two elements into it and returns (+ 2 (send orig-bag 'count 5)) S. Ducasse 7

The problem Technically you can pass to fnb a Set object as well. Just

The problem Technically you can pass to fnb a Set object as well. Just as a Bag, a Set object accepts messages put and count. However applying fnb to a Set object will break the function's post-condition Therefore, passing a set object where a bag was expected changes behavior of some program. According to the Liskov Substitution Principle (LSP), a Set is not substitutable for a Bag -- a Set cannot be a subtype of a Bag. S. Ducasse 8

Another function (define (fns set) (send set 'put 5) (send set 'count 5)) The

Another function (define (fns set) (send set 'put 5) (send set 'count 5)) The behavior of this function is: given a Set, the function adds an element into it and returns 1. S. Ducasse 9

Problem two If you pass to this function a bag (which -- just as

Problem two If you pass to this function a bag (which -- just as a set -- replies to messages put and count), the function fns may return a number greater than 1. This will break fns's contract, which promised always to return 1. S. Ducasse 10

Finally Therefore, from the OO point of view, neither a Bag nor a Set

Finally Therefore, from the OO point of view, neither a Bag nor a Set are a subtype of the other. Bag and Set only appear similar. The interface or an implementation of a Bag and a Set appear to invite subclassing of a Set from a Bag (or vice versa). Doing so however will violate the LSP -- and you have to brace for very subtle errors. Sets and Bags are very simple types, far simpler than the ones you deal with in a production code. either. It's manual work -- you have to see the problem S. Ducasse 11

Watch out Alas, LSP when considered from an OOP point of view is undecidable.

Watch out Alas, LSP when considered from an OOP point of view is undecidable. You cannot count on a compiler for help in pointing out an error. You cannot rely on regression tests S. Ducasse 12

In C++ typedef int const * Coll. Iterator; class CBag { public: int size(void)

In C++ typedef int const * Coll. Iterator; class CBag { public: int size(void) const; virtual void put(const int elem); int count(const int elem) const; virtual bool del(const int elem); Coll. Iterator begin(void) const; Coll. Iterator end(void) const; // Primitive but will do // The number of elements in the bag // Put an element into the bag // Count the number of occurrences // of a particular element in the bag // Remove an element from the bag // Return false if the element // didn't exist // Standard enumerator interface CBag(void); virtual CBag * clone(void) const; // Make a copy of the bag private: // implementation details elided }; S. Ducasse 13

CSet class CSet : public CBag { public: bool memberof(const int elem) const {

CSet class CSet : public CBag { public: bool memberof(const int elem) const { return count(elem) > 0; } // Overriding of CBag: : put void put(const int elem) { if(!memberof(elem)) CBag: : put(elem); } CSet * clone(void) const { CSet * new_set = new CSet(); *new_set += *this; return new_set; } CSet(void) {} }; S. Ducasse 14

Summary Subtyping. . . S. Ducasse 15

Summary Subtyping. . . S. Ducasse 15