[ANSI-Smalltalk] Behaviour of #collect:

Richard O'Keefe ok at cs.otago.ac.nz
Fri Sep 26 04:25:30 BST 2008


On 25 Sep 2008, at 9:40 pm, Andres Valloud wrote:

> Or this?...
>
> 'abc' collect: [:x | x codePoint] into: Array

Four flaws with this.

(1) Collecting "into" something generally means collecting
     into an existing collection, not collecting into a class.
     This will certainly conflict with existing libraries that
     have a #collect:into: method.

     My own library used to distinguish between #collect:into:
     (existing object) and #collect:intoNew: (new instance of
     class), before I junked them as too difficult to get right.
     Implementing <class> withAll:collect: turned out to be far
     less work, and far easier to use.

     Compare a corrected version of this,
	s := 'abc'.
	s collect: [:x | x codePoint] into: (Array new: s size)
     with
	Array withAll: 'abc' collect: [:x | x codePoint].

(2) How does collect:intoNew: (assuming the name to be fixed)
     know what message to send to the class?  #new: is _not_
     always the right thing to use.

(3) What happens if the Class argument is not a collection class?
     'abc' collect: [:x | x codePoint] into: Socket
     With <class> withAll: <collection> collect: <block>,
     collections that aren't collection classes just don't implement
     the method; end of story.  They also know how to make themselves
     big enough.

(4) What if you want to create a read-only collection?
     This was the killer issue for me:  I have ReadOnlyArray,
     ReadOnlyByteArray, ReadOnlyBooleanArray, and ReadOnlyString,
     and was thinking of introducing more read-only classes.
     It was the ANSI standard's insistence that literal arrays and
     strings were read-only that decided me to create some classes
     that they could belong to.  I have come to value ReadOnlyString
     highly.  Now I *can* do

	ReadOnlyString withAll: #(65 66 67)
                        collect: [:each | Character codePoint: each]

     because ReadOnlyString is in charge; it can decide exactly how to
     do this, and can do whatever it would have done for #withAll:.
     But it *can't* be done from the outside.  That's the nature of
     the read-only beast.

Many of these issues boil down to the quintessential question in
placing any Smalltalk method:  Which object should be in charge?
Which has the knowledge?  Which is _able_ to do the operation?

I am aware of collect-into in Common Lisp, and have used it, which
is why I first tried that in Smalltalk myself.  That was when I
remembered why I stopped using it in Lisp.




More information about the ANSI-Smalltalk mailing list