case study the number hierarchy
play

Case Study: The Number Hierarchy Goal: Develop feel for programming - PowerPoint PPT Presentation

Case Study: The Number Hierarchy Goal: Develop feel for programming in the large Issues well consider along the way: Class design What methods go where? Invariants Class methods establish invariants Instance methods


  1. Case Study: The Number Hierarchy Goal: Develop feel for programming in the large Issues we’ll consider along the way: • Class design – What methods go where? • Invariants – Class methods establish invariants – Instance methods must maintain them • Information hiding – “semi-private” methods for like objects – Double-dispatch when argument form matters.

  2. The Number Hierarchy Object Magnitude Number Integer Fraction Float

  3. Instance protocol for Magnitude equality (like Magnitudes) = aMagnitude comparison (ditto) < aMagnitude comparison (ditto) > aMagnitude <= aMagnitude comparison (ditto) comparison (ditto) >= aMagnitude minimum (ditto) min: aMagnitude maximum (ditto) max: aMagnitude Subclasses: Date , Natural • Compare Date with Date , Natural w/ Natural , . . .

  4. Implementation of Magnitude : Reuse (class Magnitude ; abstract class [subclass-of Object] (method = (x) (self subclassResponsibility)) ; may not inherit = from Object (method < (x) (self subclassResponsibility)) (method > (y) (y < self)) (method <= (x) ((self > x) not)) (method >= (x) ((self < x) not)) (method min: (aMag) ((self < aMag) ifTrue:ifFalse: {self} {aMag})) (method max: (aMag) ((self > aMag) ifTrue:ifFalse: {self} {aMag})) )

  5. The Number Hierarchy, Reprise Object Magnitude Number Integer Fraction Float

  6. Instance protocol for Number negated reciprocal absolute value abs addition + aNumber - aNumber subtraction multiplication * aNumber division (may answer a Fraction !) / aNumber isNegative sign check sign check isNonnegative sign check isStrictlyPositive coerce: aNumber class of receiver, value of argument conversion asInteger conversion asFraction conversion asFloat

  7. Object-oriented design Given that class Number inherits from class Magnitude , which of these methods of class Number can be implemented in terms of others? negated coerce: * reciprocal / asInteger abs isNegative asFraction + isNonnegative asFloat - isStrictlyPositive

  8. Concrete Number Methods (method - (y) (self + (y negated))) (method abs () ((self isNegative) ifTrue:ifFalse: {(self negated)} {self})) (method / (y) (self * (y reciprocal))) (method isNegative () (self < (self coerce: 0))) (method isNonnegative () (self >= (self coerce: 0))) (method isStrictlyPositive () (self > (self coerce: 0)))

  9. Abstract Number Methods (class Number [subclass-of Magnitude] ; abstract class ;;;;;;; arithmetic (method + (aNumber) (self subclassResponsibility)) (method * (aNumber) (self subclassResponsibility)) (method negated () (self subclassResponsibility)) (method reciprocal () (self subclassResponsibility)) ;;;;;;; coercion (method asInteger () (self subclassResponsibility)) (method asFraction () (self subclassResponsibility)) (method asFloat () (self subclassResponsibility)) (method coerce: (aNumber) (self subclassResponsibility)) )

  10. Extended Number Hierarchy Object Magnitude Natural Number Integer Fraction Float SmallInteger LargeInteger LargePositiveInteger LargeNegativeInteger

  11. Example class Fraction: Initialization (class Fraction [subclass-of Number] [ivars num den] ;; invariants: lowest terms, minus sign on top ;; maintained by divReduce, signReduce (class-method num:den: (a b) ((self new) initNum:den: a b)) (method initNum:den: (a b) ; private (self setNum:den: a b) (self signReduce) (self divReduce)) (method setNum:den: (a b) (set num a) (set den b) self) ; private .. other methods of class Fraction ... )

  12. Information revealed to self Instance variables num and den • Directly available • Always and only go with self Object knows its own representation, invariants, private methods: (method asFraction () self) (method print () (num print) (’/ print) (den print) self) (method reciprocal () (((Fraction new) setNum:den: den num) signReduce))

  13. Information revealed to others How would you implement coerce: ? (Value of argument, representation of receiver) (method asFraction () self) (method print () (num print) (’/ print) (den print) self) (method reciprocal () (((Fraction new) setNum:den: den num) signReduce)) (method coerce: (aNumber) ...) Saved: Number protocol includes asFraction !

  14. Information revealed to others How would you implement coerce: ? • Value of argument, rep of receiver • Challenge: Can’t access rep of argument! (method asFraction () self) (method print () (num print) (’/ print) (den print) self) (method reciprocal () (((Fraction new) setNum:den: den num) signReduce)) (method coerce: (aNumber) (aNumber asFraction)) Saved: Number protocol includes asFraction !

  15. The Number Hierarchy, Reprise How to implement comparisons on Fraction s? Object Magnitude Number Integer Fraction Float

  16. Instance protocol for Magnitude , Reprise How to implement comparisons on Fraction s? equality (like Magnitudes) = aMagnitude comparison (ditto) < aMagnitude > aMagnitude comparison (ditto) comparison (ditto) <= aMagnitude comparison (ditto) >= aMagnitude minimum (ditto) min: aMagnitude maximum (ditto) max: aMagnitude Subclasses: Date , Natural • Compare Date with Date , Natural w/ Natural , . . .

  17. Implementing comparison for Fraction s Alas! Cannot see representation of argument How will you know “equal, less or greater”?

  18. Implementing comparison for Fraction s Alas! Cannot see representation of argument Protocol says “like with like”? Extend the protocol (method num () num) ; extension, semi-private (method den () den) ; extension, semi-private (method = (fr) ((num = (fr num)) and: {(den = (fr den))})) (method < (fr) ((num * (fr den)) < ((fr num) * den)))

  19. Extended protocol: Multiply two fractions How will you multiply two fractions?

  20. Extending the protocol to multiply fractions How will you multiply two fractions? (method * (aFraction) (((Fraction new) setNum:den: (num * (aFraction num)) (den * (aFraction den))) divReduce))

  21. Information access in an open system Number protocol: like multiplies with like What about large and small integers? • How to multiply two small integers? • How to multiply two large integers? How is algorithm known? Each object knows its own algorithm: • Small: Use machine-primitive multiplication • Large: Multiply magnitudes; choose sign

  22. Review: Two kinds of knowledge I can send message to you: • I know your protocol I can inherit from you: • I know my subclass responsibilities

  23. Knowledge of protocol Three levels of knowledge: 1. I know only your public methods Example: send select: to any collection 2. You are like me: share semi-private methods Example: send * or + to Fraction 3. I must get to know you: double dispatch Example: send * to + to any integer

  24. Double dispatch: Extending open systems Design constraints: • Large integers and small integers are both Integer s • Messages = , < , + , * ought to mix freely • Large integers have a unique private protocol They implement different algorithms than small integers.

  25. Double dispatch: Forms of argument Laws of multiplication: (:+ n) * (:- m) == :- (n * m) (:+ n) * (:+ m) == :+ (n * m) (:+ n) * small == (:+ n) * (small asLargeInteger) But! Can’t distinguish forms of argument Solution: “Dispatch laws” (:+ n) * (:- m) == ((:- m) timesLP: self) (:+ n) * (:+ m) == ((:+ m) timesLP: self) (:+ n) * small == (small timesLP: self) Argument to timesLP: • Understands “large positive integer” protocol

  26. Double dispatch codes operation & protocol Example messages: • timesLP : I answer the large-positive integer protocol, multiply me by yourself • plusSP : I answer the small-integer protocol, add me to yourself Message encodes • Operation to be performed • Protocol accepted by argument

  27. Double dispatch to implement addition How do you act? 1. As small integer, you receive “add large positive integer N by self ” 2. As small integer, you receive “add small integer n to self ” 3. As large positive integer, you receive “add large positive integer N by self ” 4. As large positive integer, you receive “add small integer n to self ”

  28. Your turn: Double dispatch to implement multiplication How do you act? 1. As small integer, you receive “multiply large positive integer N by self ” 2. As small integer, you receive “multiply small integer n to self ” 3. As large positive integer, you receive “multiply large positive integer N by self ” 4. As large positive integer, you receive “multiply small integer n to self ”

  29. Your turn: Using double dispatch On what class does each method go? A. (method + (aNumber) (aNumber addSmallIntegerTo: self)) B. (method * (anInteger) (anInteger multiplyByLargePositiveInteger: self)) (See the “double dispatch”: + then addSmallIntegerTo: )

  30. Information-hiding summary Three levels 1. I use your public protocol 2. We are alike; I add our semi-private protocol 3. Your protocol is revealed by double dispatch

  31. Extra: Dealing with overflow New law for multiplication: (self * small) = ((primitive mulWithOverflow self small {((self asLargeInteger) * small)}) value)) Primitive is not a method • Answers good block or exception block • Answer is then sent value

Recommend


More recommend