[squeak-dev] String >> #numArgs

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Mon Dec 16 21:38:14 UTC 2019


Le lun. 16 déc. 2019 à 16:54, Levente Uzonyi <leves at caesar.elte.hu> a
écrit :

> 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.
>
>
I find evaluable Symbol very convenient and expressive enough.
(aCollection select: #odd)  , (aCollection collect: #squared) ,
(aCollection reduce: #+).

However, it's kind of abusing the purpose of Symbol class.
We should avoid a Frog class wanting to become bigger than an Ox class
(never mind, probably a joke for french
https://fr.wikipedia.org/wiki/La_Grenouille_qui_se_veut_faire_aussi_grosse_que_le_b%C5%93uf
)

We can cheat as long as we don't get caught, but with numArgs it sounds
like we got caught...



> >
> > > 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.
>
>
Since we got caught, we now require two different meanings indeed,
the number of arguments expected by the Symbol used as a selector
the number of arguments expected by the Symbol used as evaluable

The alternative would be to send a message for transforming a Symbol into
an evaluable thing...
Like for SortFunction we can send (points sorted: #x ascending , #y
descending)

I don't have good ones in mind, maybe something like (aCollection select:
#odd asLambda)... Or #asBlock if we really want to compile a Block on the
fly (that's an implementation detail IMO)...


>
> > > 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.
>
> If compiled once and used many, maybe.

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
>
> I have always prefered seeing the other way arround, key first - value
last like in keyAndValuesDo: rather than doWithIndex:
even though this does not lend itself to cull:cull:
And we could also create associations with (collection collectX: #->)
Otherwise we need <- like in the other thread :)


> 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
> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20191216/533105b2/attachment-0001.html>


More information about the Squeak-dev mailing list