Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!uwvax!rutgers!ames!ucbcad!ucbvax!hplabs!hp-pcd!orstcs!budd From: budd@orstcs.cs.ORST.EDU Newsgroups: comp.lang.smalltalk Subject: addition Message-ID: <245100011@orstcs> Date: Thu, 20-Aug-87 13:51:00 EDT Article-I.D.: orstcs.245100011 Posted: Thu Aug 20 13:51:00 1987 Date-Received: Sun, 23-Aug-87 05:13:41 EDT Lines: 87 Nf-ID: #N:orstcs:245100011:000:4301 Nf-From: orstcs.cs.ORST.EDU!budd Aug 20 10:51:00 1987 Let me put in my ha'pennys worth here (inflation may have raised its value to two cents by now, but certainly no more than that). In response to the adding addition to points question, almost everybody pointed to Ingalls article on double polymorphism. Johnson even said > ... 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. Playing the devil's advocate here, let me disagree. To see why, imagine the following thought experient. Suppose we initially had only two kinds of numbers, say Integers and Floats, organized using this scheme. Now you want to add a third kind, say Fractions. To implement addition for fractions, you need the message + in class Fraction, which merely invokes the message addFraction: in class fraction, but now you need to implement addFraction: in Integer as well as Float (as well as implementing addInteger: and addFloat: in class Fraction). To be precise, every class that is able to be added to other quantities must know about ALL other such classes, EXPLICITLY. If we have N such objects, this requires N**2 methods. Lets keep a table of the new methods we have added class Integer Fraction Float addFract: + addFract: addFract: addInteger: addFloat: Now consider the technique based on coercion and generality. To implement Fraction, we assign it a generaly number, presumably between Integer and Fraction. If we try to add an Integer to a fraction, since the generality of Fraction is higher, it will be passed the Coerce message. In this case, coersion is easy and the method in class Fraction can merely make a new fraction out of the integer. Similarly, in we try to add a fraction to a float, the coersion message will go to class Float, which will pass asFloat to the fraction; again, we need only implment this message in class Fraction. So we can add Fractions without adding ANY new methods to the other classes. class Integer Fraction Float + coerce: asFloat generality Now admittedly, this works only because I assumed a rule for making something with less generality into a fraction in class Fraction (namely, put it over 1 in a new Fraction). If I didn't want to make this assumption, I could have added the message asFraction to class Integer (and any other less general classes). But in many cases of interest (making a non-complex into a complex, making a number into a polynomial) such simple rules are exactly what you want; and these can be added to this scheme with no more difficulty than we encountered when we added Fractions. For example, let us continue our thought experiment by adding the ability to add +. In the double polymorphism scheme, we need to add the messages addInteger:, addFraction:, addFloat: and whatever other types of numbers we have, to class Point. In addition, we need to add the message addPoint: to all the exisiting addable classes. On the other hand, in the coersion scheme, we need only assign Points a generality value higher than any number, and add the message coerce: to class Point, which returns a point with the number in both positions. (There is a slight bit more work involved here, unless we want to make Point a subclass of Number, since we have to insure that the proper coersions get called for). So it would seem to me that in this particular case, the generality/coersion scheme uses far fewer methods and is easier to generalize than the double polymorphism technique. Now, to hop over the fence, I too always feel a bit a guilt whenever I explictly test the class of an object. Thus I always use isKindOf:, rather than isMemberOf:, so I at least can subclass without any problem. But, as Josh Susser at parkplace said: > ... Who really cares what > class an object is as long as it behaves correctly anyway? and clearly testing explicitly the class of an object violates this principle. In this particular case, however, the alternative seems worse. --tim budd budd@cs.orst.edu, {hp-pcd,tektronix}!orstcs!budd p.s. Version two of Little Smalltalk should be posted to comp.src.unix in a few days. Look for it.