binary selectors ambiguity and space
hmm at heeg.de
Wed May 17 17:38:49 UTC 2006
Duncan Mak wrote:
> On 5/17/06, Hans-Martin Mosner <hmm at heeg.de> 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
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
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.
>> 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
> 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'])
namesBeginningWithZ := (names select: [:each | each startsWith: 'z'])
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.
category: 'namesBeginningWithA' predicate: [:obj | obj startsWith: 'a'];
category: 'namesBeginningWithZ' predicate: [:obj | obj startsWith: 'z'].
categorizer categorizeAll: names.
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.
More information about the Squeak-dev