stoop 416-lsp

15
S.Ducasse 1 QuickTime™ TIFF (Uncompr are needed t Stéphane Ducasse [email protected] http://www.listic.univ-savoie.f r/~ducasse/ LSP Stéphane Ducasse --- 2005

Upload: the-world-of-smalltalk

Post on 27-Jan-2015

144 views

Category:

Documents


1 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Stoop 416-lsp

S.Ducasse 1

QuickTime™ and aTIFF (Uncompressed) decompressorare needed to see this picture.

Stéphane [email protected]://www.listic.univ-savoie.fr/~ducasse/

LSP

Stéphane Ducasse --- 2005

Page 2: Stoop 416-lsp

S.Ducasse 2

License: CC-Attribution-ShareAlike 2.0http://creativecommons.org/licenses/by-sa/2.0/

Page 3: Stoop 416-lsp

S.Ducasse 3

A step deeper in Subtyping...

Page 4: Stoop 416-lsp

S.Ducasse 4

Liskov Substitution Principle (LSP)

if for each object o1 of type S there is another 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, "Data Abstraction and Hierarchy," SIGPLAN Notices, 23,5 (May 1988)

Page 5: Stoop 416-lsp

S.Ducasse 5

A Simple BagWe 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).

Page 6: Stoop 416-lsp

S.Ducasse 6

A Simple SetLikewise, 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).

Page 7: Stoop 416-lsp

S.Ducasse 7

A Bag Function(define (fnb bag) (send bag 'put 5) (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))

Page 8: Stoop 416-lsp

S.Ducasse 8

The problemTechnically 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.

Page 9: Stoop 416-lsp

S.Ducasse 9

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.

Page 10: Stoop 416-lsp

S.Ducasse 10

Problem twoIf 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.

Page 11: Stoop 416-lsp

S.Ducasse 11

FinallyTherefore, 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

Page 12: Stoop 416-lsp

S.Ducasse 12

Watch outAlas, 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

Page 13: Stoop 416-lsp

S.Ducasse 13

In C++typedef int const * CollIterator; // Primitive but will doclass CBag { public: int size(void) const; // The number of elements in the bag virtual void put(const int elem); // Put an element into the bag int count(const int elem) const; // Count the number of occurrences

// of a particular element in the bag virtual bool del(const int elem); // Remove an element from the bag

// Return false if the element// didn't exist

CollIterator begin(void) const; // Standard enumerator interface CollIterator end(void) const;

CBag(void); virtual CBag * clone(void) const; // Make a copy of the bag private:

// implementation details elided};

Page 14: Stoop 416-lsp

S.Ducasse 14

CSetclass 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) {}};

Page 15: Stoop 416-lsp

S.Ducasse 15

Summary

Subtyping...