preston@felix.UUCP (Preston Bannister) (08/04/87)
I have been writing a set of class definitions to support graphics in Little Smalltalk from the descriptions in the Smalltalk-80 books. The class Point responds to '+'. The examples show both: aPoint + aPoint i.e. (1 @ 2) + (3 @ 4) = (4 @ 6) and aPoint + aNumber i.e. (1 @ 2) + 3 = (4 @ 5) What I don't see is how to write the method for '+' without explicitly testing the class of the parameter. Something like: + delta (delta class == Point) ifTrue: [^ Point new x: (self x + (delta x)) y: (self y + (delta y)) ] ifFalse: [^ Point new x: (self x + delta) y: (self y + delta) ] (This may not be correct Smalltalk. I'm not that familiar with the language and the book is not in front of me.) Somehow I would have expected to write two methods: + aPoint ^ Point new x: (self x + (delta x)) y: (self y + (delta y)) + aNumber ^ Point new x: (self x + delta) y: (self y + delta) But this doesn't seem possible. Am I missing something?? ======================================== Preston L. Bannister USENET : ucbvax!trwrb!felix!preston BIX : plb CompuServe : 71350,3505 GEnie : p.bannister -- ======================================== Preston L. Bannister USENET : ucbvax!trwrb!felix!preston BIX : plb CompuServe : 71350,3505 GEnie : p.bannister
stevev@tekchips.TEK.COM (Steve Vegdahl) (08/05/87)
In article <4357@felix.UUCP>, preston@felix.UUCP (Preston Bannister) writes: > > The class Point responds to '+'. The examples show both: > aPoint + aPoint i.e. (1 @ 2) + (3 @ 4) = (4 @ 6) > and > aPoint + aNumber i.e. (1 @ 2) + 3 = (4 @ 5) > What I don't see is how to write the method for '+' without explicitly > testing the class of the parameter. Something like: > > + delta > (delta class == Point) > ifTrue: [^ Point new x: (self x + (delta x)) y: (self y + (delta y)) ] > ifFalse: [^ Point new x: (self x + delta) y: (self y + delta) ] I believe that most Smalltalk images have a coercion selector "asPoint", where 3@7 asPoint --> 3@7 but 6 asPoint --> 6@6 Then your '+' method for Point looks something like: + delta | temp | temp <- delta asPoint ^(self x + temp x) @ (self y + temp y) Steve Vegdahl Computer Research Lab Tektronix Labs Beaverton, Oregon
patc@tekcrl.TEK.COM (Pat Caudill) (08/05/87)
>In article <4357@felix.UUCP>, preston@felix.UUCP (Preston Bannister) writes: > > The class Point responds to '+'. The examples show both: > aPoint + aPoint i.e. (1 @ 2) + (3 @ 4) = (4 @ 6) > and > aPoint + aNumber i.e. (1 @ 2) + 3 = (4 @ 5) > What I don't see is how to write the method for '+' without explicitly > testing the class of the parameter. Something like: Besides using the method that Steve Vegdahl describes, I would like to suggest the method pointed out by Dan Ingalls in a paper at the OOPSLA-86 conference. I will use the convention, as he did, of showing the class of the receiver in <> before the message. <Point> + aValue ^aValue pointPlus: self Then define pointPlus in both number and point as <Point> pointPlus: aPoint ^ (self x + aPoint x) @ (self x + aPoint y) <Number> pointPlus: aPoint ^ (self + aPoint x) @ (self + aPoint y) The full reference is: Daniel H. H. Ingalls, "A Simple Technique for Handling Multiple Polymorphism" OOPSLA'86 Conference Proceedings (Sigplan Notices Vol 21 #1 (Nov 1986)) pp 347. I hope this helps. Pat Caudill patc@tekcrl.TEK.COM
susser@parcvax.Xerox.COM (Josh Susser) (08/05/87)
In article <4357@felix.UUCP> preston@felix.UUCP (Preston Bannister) writes: > >I have been writing a set of class definitions to support graphics in >Little Smalltalk from the descriptions in the Smalltalk-80 books. > >The class Point responds to '+'. The examples show both: > aPoint + aPoint i.e. (1 @ 2) + (3 @ 4) = (4 @ 6) >and > aPoint + aNumber i.e. (1 @ 2) + 3 = (4 @ 5) > >What I don't see is how to write the method for '+' without explicitly >testing the class of the parameter. Something like: > > + delta > (delta class == Point) > ifTrue: [^ Point new x: (self x + (delta x)) y: (self y + (delta y)) ] > ifFalse: [^ Point new x: (self x + delta) y: (self y + delta) ] > >Somehow I would have expected to write two methods: > + aPoint > ^ Point new x: (self x + (delta x)) y: (self y + (delta y)) > + aNumber > ^ Point new x: (self x + delta) y: (self y + delta) >But this doesn't seem possible. > >Am I missing something?? > >======================================== >Preston L. Bannister >USENET : ucbvax!trwrb!felix!preston >BIX : plb >CompuServe : 71350,3505 >GEnie : p.bannister Your instincts are right - explicitly testing the class of an object is an evil thing to do. Besides, what if you want to add a subclass of Point? Or something that just behaves like a Point? There are two good ways to handle a situation like this. They both involve writing more than one method. The first way, you make sure that the argument is a Point, by coercing it if necessary. Like so: Integer: asPoint ^self@self Point: asPoint ^self + delta delta <- delta asPoint. ^(x + delta x)@(y + delta y) The other way is using a technique known as multiple polymorhism: Integer: plusPoint: aPoint ^(self + aPoint x)@(self + aPoint y) Point: plusPoint: aPoint ^(x + aPoint x)@(y + aPoint y) + delta ^delta plusPoint: self Both of these techniques are nicer than explicitly testing the class of the argument. The advantage here is that you can then add anything to a Point as long as is understands "asPoint" or "plusPoint:". Who really cares what class an object is as long as it behaves correctly anyway? --Josh Susser susser.pasa@xerox.com susser@parcvax.xerox.com When the going gets tough, it takes a brave man to lay back and party.
chips@usfvax2.UUCP (Chip Salzenberg) (08/06/87)
In article <4357@felix.UUCP>, preston@felix.UUCP writes: > I have been writing a set of class definitions to support graphics in > Little Smalltalk from the descriptions in the Smalltalk-80 books. > > The class Point responds to '+'. The examples show both: > > aPoint + aPoint i.e. (1 @ 2) + (3 @ 4) = (4 @ 6) > and > aPoint + aNumber i.e. (1 @ 2) + 3 = (4 @ 5) > > What I don't see is how to write the method for '+' without explicitly > testing the class of the parameter. > > Preston L. Bannister > USENET : ucbvax!trwrb!felix!preston Perhaps you could implement the method asPoint in the class Integer: asPoint "Return a Point with x and y both equal to self." ^self @ self. Then, in class Point: asPoint "Return self." ^self. and, then the method you wanted: + delta "Return the sum of two points. Delta may be an integer." | aPoint | aPoint := delta asPoint. ^(self x) + (aPoint x) @ (self y) + (aPoint y). This may not be very fast, but it would work. -- Chip Salzenberg UUCP: "uunet!ateng!chip" or "chips@usfvax2.UUCP" A.T. Engineering, Tampa Fidonet: 137/42 CIS: 73717,366 "Use the Source, Luke!" My opinions do not necessarily agree with anything.
johnson@uiucdcsp.cs.uiuc.edu (08/06/87)
The + method for Point in Smalltalk-80 converts the argument to a point
and then adds it. It looks something like
+ anArg
| aPoint |
aPoint <- anArg asPoint.
^(x + aPoint x) @ (y + aPoint y)
The asPoint message to a Point returns the receiver, while the asPoint
message to a number returns (self @ self).
This seems to me a kludge. A better solution is to use "double dispatching"
to pick the method based on the classes of both the receiver and the
argument. Dan Ingals had a paper describing this in OOPSLA'86. The basic
idea is that the + method for Point would look something like
+ anArg
^anArg addToPoint: self
The class of anything that might ever be added to a point would then need
an addToPoint: method. You can do this with all the number classes and
the arithmetic operators. It results in a nicer system than the one in
Smalltalk-80 based on "coercion", especially if you want to have matrices,
polynomials, functions, etc. as part of your arithmetic.
I teach my students that good Smalltalk code should NEVER explicitly test
the class of an object. Double dispatching is usually a better alternative.