binary selectors ambiguity and space

Hans-Martin Mosner 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 
> '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



More information about the Squeak-dev mailing list