Duncan Mak wrote:
> On 5/17/06, Hans-Martin Mosner <[hidden email]> wrote: > >> >> The first is easy, but in my opinion does not add much value - "aNumber >> next" does not help me understand the code better than "aNumber + 1" >> does. And of course, it re-uses a selector which is already used in the >> stream hierarchy and means something completely different. > > > I agree the name might not be the best. I think in Ruby, they have > 'succ'. Yup, succ (or successor) would be more natural. Still it is no great advantage over aNumber+1 IMO :-) > >> The second one is not possible with Smalltalk's semantics. Messages are >> sent to objects, not to variables. So whatever message you send to >> variable x, it can't cause x to point to another object (with the >> exception of #become: but that's a special case). Since numeric objects >> are immutable, you need to have the assignment x := x+1 either >> implicitly or explicitly somewhere. > > > I was thinking of using become: to implement something like this, yeah. But that would get you into trouble. First, become: is not applicable to immediate objects. And second, it would change all slots pointing to that object. You might try this (I'm using floating point numbers because they can be used with become:): | a b | a := Float pi. b := a. a become: 3.0. b printString > >> I'd like to know concrete use cases where you would prefer an increment >> method over an explicit x := x+1. My gut feeling is that such cases >> probably could be handled even better by still other constructs (for >> example, collections or streams), but of course this can't be said >> generally for all cases. > > > I think you're probably right, but still I think having a particular > message send for 'increment' is not a bad idea in general. I think > something like this is most often used when implementing some sort of > counter. > > It is true that > > names select: [:each | each startsWith: 'a'] size > > is more elegant than something like: > > names do: [:each | each startsWith: 'a' ifTrue: [count := count + 1] > > but what if you want to count multiple conditions in a single iteration? First think about which code is more readable: namesBeginningWithA := (names select: [:each | each startsWith: 'a']) size. namesBeginningWithZ := (names select: [:each | each startsWith: 'z']) size. or namesBeginningWithA := Counter new. namesBeginningWithZ := Counter new. names do: [:each | (each startsWith: 'a') ifTrue: [namesBeginningWithA increment]. (each startsWith: 'z') ifTrue: [namesBeginningWithZ increment]. ] ? Iterating is pretty cheap. And if you worry about performance, you still can optimize later. For example, you could implement a class Categorizer and use it like that: categorizer := Categorizer new. categorizer justCountElements; allowDuplicates. categorizer category: 'namesBeginningWithA' predicate: [:obj | obj startsWith: 'a']; category: 'namesBeginningWithZ' predicate: [:obj | obj startsWith: 'z']. categorizer categorizeAll: names. categorizer categories Granted, this code is even larger than the second example above, and maybe it's even less readable. That's what you get when I invent something off the top of my head. Some further study would probably come up with a much more elegant solution. Cheers, Hans-Martin |
In reply to this post by Duncan Mak-2
On 17-May-06, at 9:36 AM, Duncan Mak wrote: > > I was thinking of using become: to implement something like this, > yeah. You can't do that. Smallintegers cannot be become:'d. Other numbers shouldn't be. A number is a number - a manifest object that is what it is. You *cannot* increment a number. There is nothing you can do to '3' to make it anything but '3'. I fear you're still stuck in the C rape-and-pillage mindset where you get to plunder memory locations and have your wicked way with them like some rampaging Assyrian horde-member. It just isn't how Smalltalk works, so try to put that aside. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Fractured Idiom:- RESPONDEZ S'IL VOUS PLAID - Honk if you're Scots |
In reply to this post by Hans-Martin Mosner
>Duncan Mak wrote:
>>I have always wondered why the standard image doesn't come with a next method and an increment method for Integers, where next would answer x + 1 and increment would set x to be x + 1. and Hans-Martin Mosner <[hidden email]> replied... >The first is easy, but in my opinion does not add much value - "aNumber next" does not help me understand the code better than "aNumber + 1" does. And of course, it re-uses a selector which is already used in the stream hierarchy and means something completely different. > >The second one is not possible with Smalltalk's semantics. Messages are sent to objects, not to variables. So whatever message you send to variable x, it can't cause x to point to another object (with the exception of #become: but that's a special case). Since numeric objects are immutable, you need to have the assignment x := x+1 either implicitly or explicitly somewhere. > >I'd like to know concrete use cases where you would prefer an increment method over an explicit x := x+1. My gut feeling is that such cases probably could be handled even better by still other constructs (for example, collections or streams), but of course this can't be said generally for all cases. We have several times contemplated a Smalltalk with the completely complementary point of view about integers - namely that the system is built around accumulator objects - mutable holders of raw integer values. If you follow this through, it has significant benefits: 1. You get a homogeneous address space - no more tag bits to check for SmallInts. 2. The format and range of integers is the same as C and native code. 3. Patterns like "i increment" can be wicked fast because the receiver knows the type, can use a native increment instruction, and can use the native overflow test to check bounds. 4. The extension to Floats has similar benefits, plus iterative code need not create tons of little objects for intermediate values (ie (0.0 to: 10000 by: 0.01) do: [] would not create a million Floats Of course literals would use read-only subclasses of these objects. I post this just because it's fun to think about and share such alternate approaches. In spite of these attractive characteristics, I like the functional composition of immutable objects as the basic model to teach and work with, and I think the average newbie is a bit more ready for integers than accumulators. - Dan |
In reply to this post by timrowledge
Likely it's constructive to use the source, er Tim, so lets consider
what + really does... foo := 1 + 2 compiled results in bytecodes 5 <76> pushConstant: 1 6 <77> pushConstant: 2 7 <B0> send: + 8 <68> popIntoTemp: 0 For other forms it would be pushOops, pushOops, + and popIntoSomething. The bytecode prim is on Interpreter>> bytecodePrimAdd "normally you think we would invoke the message send, but that is slow, we want to avoid that if we are dealing with special cases, like SmallIntegers or Floats, We grab the two values off the stack then see if both are integers, if so we add them together, then see if the result is still a SmallInteger, if so we pop the stack and push the result, and process the next byte code, we are done. If one or more of the parms are not SmallIntegers we attempt to do a floating point add, which loads the values as Double Float or converts from SmallInteger to Double Float. If that fails we end up scheduling a proper message send of '+' to the receiver. Note how we at the end pop the 2 values off the stack then push the result onto the stack, then after bytecode finishs the top item on the stack is the value we store somewhere, like back into an instance variable, class variable, temporary slot... | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [result := (self integerValueOf: rcvr) + (self integerValueOf: arg). (self isIntegerValue: result) ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: result). ^ self fetchNextBytecode "success"]] ifFalse: [successFlag := true. self externalizeIPandSP. self primitiveFloatAdd: rcvr toArg: arg. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]]. messageSelector := self specialSelector: 0. argumentCount := 1. self normalSend Optimizations. A few years back I considered what if they are large integers in the range of +- 2 billion and the result was a 32 bit integer, could we load as 32bit integers, do the math and store a smallInteger result or convert to largeInteger? I did write some code for that, but it was deemed a bit too specialized and really what application would need it? On 17-May-06, at 11:34 AM, tim Rowledge wrote: > > On 17-May-06, at 9:36 AM, Duncan Mak wrote: > > >> >> I was thinking of using become: to implement something like this, >> yeah. > You can't do that. Smallintegers cannot be become:'d. Other numbers > shouldn't be. A number is a number - a manifest object that is what > it is. You *cannot* increment a number. There is nothing you can > do to '3' to make it anything but '3'. > > I fear you're still stuck in the C rape-and-pillage mindset where > you get to plunder memory locations and have your wicked way with > them like some rampaging Assyrian horde-member. It just isn't how > Smalltalk works, so try to put that aside. > > > tim > -- > tim Rowledge; [hidden email]; http://www.rowledge.org/tim > Fractured Idiom:- RESPONDEZ S'IL VOUS PLAID - Honk if you're Scots > > > -- ======================================================================== === John M. McIntosh <[hidden email]> 1-800-477-2659 Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com ======================================================================== === |
In reply to this post by Nicolas Cellier-3
Dear List,
please find my resume of this thread at http://www.ba-stuttgart.de/~helbig/st80/Grammar.txt Thank you all for the insights I've got while discussing with you about Smalltalk. Greetings, Wolfgang -- Weniger, aber besser. |
Free forum by Nabble | Edit this page |