Newsgroups: comp.lang.smalltalk Path: utzoo!utgpu!cunews!knight From: knight@mrco.carleton.ca (Alan Knight) Subject: Re: Access methods - New feature ? Message-ID: <1991Apr25.141642.4560@ccs.carleton.ca> Sender: news@ccs.carleton.ca (news) Organization: Carleton University, Ottawa, Canada References: <1991Apr24.153744.24049@ccs.carleton.ca> Date: Thu, 25 Apr 1991 14:16:42 GMT In article voss@cs.uiuc.edu (Bill Voss;;;356-4652;jerry.cs.uiuc.edu) writes: >------------------------------------------------------------------------------ >First let me say thanks to all my fellow debate partners in this string, both >the posters, and the emailers. This is definitely the most fun I've had in >comp.lang.smalltalk for months. We have even managed to disagree without >slipping into a flame war, in my opinion this string is an example of USENET >at its finest. Thank you. I agree that this thread is remarkably civil and thought-provoking by USENET standards. (me) >> Suppose that I have a set of points, and that I want to sort them. >> There's no canonical sorting order for points, so I have to define >PP.R4 class "Point" method category "comparing" method "<= aPoint" method >comment says "Answer whether the receiver is 'neither below nor to the right' >of aPoint." So you can stick PP.R4 Point's directly into a sorted collection. This is not a total order. Try (0 @ 3) <= (3 @ 0) ==> false (3 @ 0) <= (0 @ 3) ==> false You can put them into a sorted collection, and you will get an answer back, but it isn't really sorted. For example, you get. (Array with: (3@0) with: (0@3)) asSortedCollection ==> SortedCollection (0@3 3@0 ) (Array with: (0@3) with: (3@0)) asSortedCollection ==> SortedCollection (3@0 0@3 ) (This is also in PP.R4, but is not likely specific to that version). > >If you need a different canonical sorting order, then yes I most definitely >would suggest adding a simple method "xyzCompare:" to class point. Then use >the simple and readable sort block [:p1 :p2 |p1 xyzCompare: p2]. Both methods >will obviously work, but there is an implicit difference in encapsulation. > I will agree that there is no particular harm done by using xyzCompare: p2, but I don't think it gains you very much over the other approach. It might be better style though, so I'll concede you this one. >> [ :point1 :point2 | point1 x <= point2 x] >Would you use that sort block if you KNEW that the internal representation of >a Point was NOT based on instance variables X and Y? I like my code to run as If I wanted to sort by x-coordinate I don't see that I would have any choice. >I`ld also either name xyzCompare: something like > orderByGodzilianSpiral: >in this case I've already written my GodzilianSpiral code when I need it again >OR > projectHack12BSorter: >in which case WHEN I later decide I didn't really need that infinite precision >asymptotically corrected aglutinated comparison, and could instead get by with >an 8 way truncated fast shuffle I only need to change code in ONE PLACE. The code for sorting should already be in one place. The sort block does not implement a sorting routine, just a comparison, and in the instances where the comparison was trivially based on a property of the object which could be considered a key (whether this is part of the representation or not). In the case of an even moderately complex comparison function I would definitely put it in a method. e.g. aPoint leqInClockwiseRadialOrderWithOrigin: anOriginPoint than: anotherPoint Although, with regard to the efficiency you like (which I think I just deleted) for an ordering by key which is expensive it is considerably more efficient to calculate the property once at the beginning and then compare keys. e.g. allPoints do: [:eachPoint | eachPoint associateProperty: (eachPoint GodzilianSpiralNumberWRT: anOrigin)]. (Pretend points have property lists hanging of them. One could also use a dictionary or some other mechanism to do this). This efficiency, however, breaks encapsulation somewhat in that you need to use a different sorting routine depending on how expensive your ordering is. >I've never done any finite element analysis, I don't think I could even tell >you what it is used for. (My, my, the state of my education.... ;-) Doing physical calculations about objects. e.g. to analyze heat flow in a weld, break the object being welded into a number (often large) of regularly shaped elements, and then evaluate your heat functions at the corners of these objects discretely rather than continuously throughout the object. > >That said, it sounds as though you are treating Points as simple Records here. >Extracting out the raw data they contain, and plugging that data into a >mathematical formula. There is nothing apriori wrong with doing this. In >such a situation the difficult portion is usually the mathematics, not the >programming. However, I wouldn't describe it as object oriented programming >either, it is programming in an imperative style using an object oriented >language. I know if someone gave me a problem which involved complex >mathematical formulas I'ld do the same thing. I'ld simply plug the formulas >into my program. Not all problems require a hammer, and not all problems >require object oriented programming. This seems to be one of those cases >where imperative is better, and imperative programming definitely DOES work >better with access methods. Good analysis of the situation. In fact, IMHO, a lot of the difference in style between OOP and non-OOP programming is in the difference in difficulty between different parts of the program. Imperative programming assumes that the difficult parts are the functions, and that data is some other stuff that functions work on. The important mental shift in OOP is that usually the data are more important, and that they should be treated as primary with functions dependent on them. However, this is not true in all domains, and certain kinds of mathematics are examples of this. For example, there are a great many integer functions in math (factorial, catalan, fibonacci, etc. etc.). The natural impulse is to add these as methods in class Integer. However, these can be very expensive to evaluate, so it's probably worth caching them, or intermediate results (e.g. for catalan it's a big win to cache intermediate C(n,k) values). These could be added as class variables in class Integer, but pretty soon this gets awfully messy. What's happening is that the mathematical functions and their associated data are becoming "heavier" than the functions strictly associated with single integers, and IMHO the correct approach is to split these functions out into a separate class or classes. This sounds a bit like what you are proposing in your P.S. i.e. >P.S. >Thinking about it a wee bit more, perhaps you could handle a mathematical >formula in a rather object oriented style by making the formula itself a >class. > >So I need to update my exceptions list. > > Using ACCESS methods is almost always undesirable EXCEPT: > 1) As class "private" methods. > 2) To encapsulate an external interface you can't easily change. > 3) To implement something not easily expressed in an object oriented style. > Such as a complex mathematical formula better expressed > in an imperative style. This sounds reasonable, although it has the potential to be dangerous given the common mentality that "object-oriented" means good and "not object-oriented" means bad. "To implement something not easily expressed in an OO style" also sounds a bit like a "To handle cases where you need to" catchall, but perhaps that's what it amounts to. Unrelated P.S. I definitely think that a Vector should be a subclass somewhere under Magnitude. In PPS, probably under ArithmeticValue, but not Number. In a number of places Smalltalk treats points like Vectors of size 2 (e.g. (3@2) * 5), but they're not well-integrated. -- -- Alan Knight knight@mrco.carleton.ca +1 613 788 5783 Support Dept. of Mechanical and Aeronautical Engineering the Carleton University, Ottawa, Ontario, Canada, K1S 5B6 LPF