[squeak-dev] String >> #numArgs

Levente Uzonyi leves at caesar.elte.hu
Mon Dec 16 15:54:48 UTC 2019


On Mon, 16 Dec 2019, Thiede, Christoph wrote:

> 
> Hi Tobias, thanks for your input!
> 
> 
> > Why not simply
> 
> >         Matrix rows: 5 columns: 6 tabulate: [:x :y | x @ y]
>> > What's wrong with blocks?
> 
> At least in scripting scenarios, they cost extra redundant characters. Symbol >> #value:value: is a known selector (at least now), so why should I always type all these redundant letters?

That's right. The sole advantage of having those methods is that they make 
writing scripts easier. IIRC, I asked here not to commit code into the 
Trunk using these "tricks". We can always use blocks, which are more 
legible for most smalltalkers, and they have better performance as well.

> 
> > A symbol should not answer to an #value: … #value:value:...
> Levente should know it, he implemented Symbol >> #value:value:.

The goal with Symbol>>value:value: was to help writing sort blcoks, but 
now we have SortFunctions for that.
The method follows the semantics of Symbol>>value:.
Since sorting doesn't require more than two parameters, I didn't even 
consider adding further value:* variants.

> However we solve this, I think, at the moment, we have an irritating inconsistency. Imho, Symbol >> #value: is not better than Symbol >> #value:value at all. And I use it every day, so I would vote for increasing the support.
> (BalloonMorph allInstancesDo: #abandon, SystemWindow select: #isInWorld, ...)
> 
> > I would then rather use withIndexCollect. It does what it says on the tin.
> At the moment, we have #collect: and #withIndexCollect: side by side. However, their implementations are almost equal, and my problem is that every method that I write to access a collection (e. g. collection accessors) can
> only support one of them. Why not exploit the fact that [:x :i | x + i] and [:x | x squared] can be distinguished by #numArgs and unify these two accessors?

#numArgs is not suitable for that if you want to mix blocks with symbols. 
Creating a new method (e.g. I saw #arity in a VW discussion) would be a 
much better option.

> 
> > you can use cull:cull: anyways.
> Interesting point. This would also simplify the approaches for our recent #to:collect: issue:
> (1 to: 5) collectX: [Color random]
> 
> Could we maybe just adapt SequenceableCollection >> #collect: to support 0 - 2 block arguments instead of exactly one? It would be nice to have this in Trunk!
> 
> > > Symbol >> #asBlock
> > that's not too bad :D > but there is already perform:withArguments:, so this should be simpler?
> 
> I would be glad to send something to the Inbox. But how do you create a block by reflection, without knowing the number of arguments?
> It looks as if there is no public interface yet and I would have to generate the byte codes manually. Or am I overlooking something?

That would be a cool feature, but it would make debugging a bit harder, 
because it would be hard to tell where those blocks come from.
On the other hand, it could significantly speed up SortFunctions.

For collectX:, you don't need anything like that. Below is a simple and 
reasonably fast implementation. Note that it still has worse performance 
than #collect:.


collectX: aValuable
 	"Evaluate aValuable with each of the receiver's elements and indices as optional arguments. Collect the resulting values into a collection like the receiver. Answer the new collection."

 	| index size newCollection |
 	newCollection := self species new: self size.
 	index := 0.
 	size := self size.
 	aValuable numArgs + (aValuable isSymbol ifTrue: [ 1 ] ifFalse: [ 0 ]) caseOf: {
 		[ 0 ] -> [
 			[ (index := index + 1) <= size ] whileTrue: [
 				newCollection at: index put: aValuable value ] ].
 		[ 1 ] -> [
 			[ (index := index + 1) <= size ] whileTrue: [
 				newCollection at: index put: (aValuable value: (self at: index)) ] ].
 		[ 2 ] -> [
 			[ (index := index + 1) <= size ] whileTrue: [
 				newCollection at: index put: (aValuable value: (self at: index) value: index) ] ] }.
 	^newCollection


Levente
[1] http://forum.world.st/The-Trunk-Collections-ar-183-mcz-td481126.html

P.S.: You may find these other discussions about this topic interesting:
http://forum.world.st/Symbol-gt-gt-value-value-td1306944.html
http://forum.world.st/Symbol-should-implement-cull-cull-td4758139.html
http://forum.world.st/Implementing-cull-cull-in-symbol-td4763781.html
http://forum.world.st/Symbol-gt-value-td3778525.html
http://forum.world.st/Musing-on-Symbol-gt-gt-value-td3367942.html

> 
> Best,
> Christoph
> 
> _________________________________________________________________________________________________________________________________________________________________________________________________________________________________
> Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Tobias Pape <Das.Linux at gmx.de>
> Gesendet: Montag, 16. Dezember 2019 13:41:03
> An: The general-purpose Squeak developers list
> Betreff: Re: [squeak-dev] String >> #numArgs  
> Hi
> 
> > On 16.12.2019, at 13:18, Thiede, Christoph <Christoph.Thiede at student.hpi.uni-potsdam.de> wrote:
> >
> > Hi all! :-)
> >
> > > Woah! This works? When and why is this useful? Does anybody recall the prime example? :-) #inject:into:?
> >
> > Yes, I believe I once used it with #inject:into:, but I don't remember. What prime example are you referring to? :)
> > My personal favorite is:
> > Matrix rows: 5 columns: 6 tabulate: #@ "for quickly setting up an example matrix :-)"
> 
> Why not simply
>         Matrix rows: 5 columns: 6 tabulate: [:x :y | x @ y]
> 
> What's wrong with blocks?
> 
> >
> > I find it rather confusing that the following does not work:
> > #raisedTo: value: 2 value: 3. "works"
> > #raisedTo:modulo: value: 2 value: 3 value: 4. "does not understand"
> > This is an inconsistency.
> 
> Yes. The first case should also bail.
> 
> A symbol answering to #perform: is IMHO borderline.
> A symbol's answer to #value should be itself.
> A symbol should not answer to an #value: … #value:value:...
> 
> 
> >
> > @Eliot:
> > > Can you give some examples of where you find you are needing to do this?
> >
> > Actually, I was trying something like this:
> > SequenceableCollection >> #collectX: aBlock
> > ^ aBlock numArgs = 2
> > ifTrue: [self withIndexCollect: aBlock]
> > ifFalse: [self collect: aBlock]].
> >
> > Now you can say:
> > #(1 2 3) collectX: [:x | x squared].
> > #(1 2 3) collectX: #squared.
> > #(1 2 3) collectX: [:x :i | x + i].
> 
> That's hacky.
> 
> I would then rather use withIndexCollect. It does what it says on the tin.
> 
> > But the following does not work:
> > #(1 2 3) collectX: #+.
> >
> > Maybe I would rather need something like #value:cull: for an optional second argument?
> >
> 
> you can use cull:cull: anyways.
> 
> > In general, from the point of scripting convenience, I would love Symbol to support many more protocols of BlockClosure. What about:
> > Symbol >> #asBlock
> > ^ self numArgs caseOf: {
> > [0] -> [[:rcvr | rcvr perform: self]].
> > [1] -> [[:rcvr :arg | rcvr perform: self with: arg]].
> > [2] -> [[:rcrv :arg1 :arg2 | rcrv perform: self with: arg1 with: arg2]].
> > ... }
> >
> that's not too bad :D
> but there is already perform:withArguments:, so this should be simpler?
> 
> Best regards
>         -Tobias
> 
> 
>


More information about the Squeak-dev mailing list