[squeak-dev] collect:thenDo: woes

Thiede, Christoph Christoph.Thiede at student.hpi.uni-potsdam.de
Wed Sep 11 10:57:25 UTC 2019


Wow, those syntactical ideas sound really interesting. However, I think is very important to keep the Smalltalk syntax as minimal as possible, as imho this is one big advantage over other common languages like C*. Smalltalk stands out by its use of self-explaining messages instead of non-intuitive keywords. So what would you think about the following?


foo asZöglfrex
    collect: [:x|x barf];
    select: [:y|y isKnorz];
    inject: Kiffle into: [:clomb :blui | clomb baz: blui]);
    sum

(Or even override #yourself instead of using #receiver.)

The relevant implementation of Zöglfrex would be quite easy:

Object subclass: #Zöglfrex
    instanceVariableNames: 'receiver'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Kernel-Objects'

Zöglfrex >> doesNotUnderstand: aMessage
    ^ receiver := aMessage sendTo: receiver


Best,

Christoph

________________________________
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Tobias Pape <Das.Linux at gmx.de>
Gesendet: Mittwoch, 11. September 2019 10:52:39
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] collect:thenDo: woes

Hi

> On 11.09.2019, at 09:42, Stéphane Rollandin <lecteur at zogotounga.net> wrote:
>
> Richard O'Keefe is making good points against the Squeak implementation of method #collect:thenDo: in the Pharo-users list:
>
> https://lists.pharo.org/pipermail/pharo-users_lists.pharo.org/2019-September/044204.html

I read it. I see his point but I am attempted to disagree.

Here's my reasoning:

#collect:thenXXX: for me implies that the block of the collect-part has to abide the same constraints as a "pure" collect.

That is, if you do
        'abc' collect: [:x | x asMorph]
and this fails, then
        'abc' collect: [:x | x asMorph] thenDo: [:m | m openInHand].
MUST also fail.

Collect is bound to the kind of collection it collects over.
We have #collect:as: for kind/species-changing collects.
So to support Richard's case, one could imagine

  |o|
  o := OrderedCollection new.
  #[3 1 4 1 5 9]
    collect: [:byte | byte asFloat] as: OrderedCollection
    thenDo: [:float | o addLast: float].
  Transcript print: o; cr.

(which makes the thenDo:-part superfluous, but I understand why the original version is that way)
or for the other example:

   #[3 1 4 1 5 9]
     collect: [:byte | byte odd ifTrue: [byte printString]
                                ifFalse: [byte]]
     as: Array
     thenSelect: [:each | each isNumber]



>
> I vote for the removal of this confusing method.

[TL;DR below]


The problem the #enumerationPart:thenOtherEnumerationPart: messages try to solve is our (otherwise helpfully) slim syntax.
Because
        (((foo collect: [:x|x barf]) select: [:y|y isKnorz]) inject: Kiffle into: [:clomb :blui | clomb baz: blui]) sum
is hard to write, error-prone and not "scriptable"[1].

Marcel Weiher added syntax for this in his Objective-SmallTalk [sic] which would rather read like

        foo collect: [:x|x barf |> select: [:y|y isKnorz] |> inject: Kiffle into: [:clomb :blui | clomb baz: blui] |> sum

or with breaks:
        foo
                collect: [:x|x barf |>
                select: [:y|y isKnorz] |>
                inject: Kiffle into: [:clomb :blui | clomb baz: blui] |>
                sum

This makes it all very data-flow-y, which can be really great to understand what's going on with one's collections.

Personally, I am not too keen on the '|>' symbolism itself, because |> is just another binary operator and would break current syntax.

However, this whole thing is close enough to cascades we already got:

        forc
                gnarf: [kelp];
                klimb;
                strosn: [:f :zz | zz klept: f];
                badummdz.

And _If_ we had something like it, I'd prefer it similarly to this.
Maybe ;; (while somewhat stupid, its practical in its own right…), or use ! (no syntactical meaning yet, aside the changeset separation, but looks strange).
The ` is free but used in RefactoringBrowser's code matching and compiler error messages, so no good candidate either.

Other syntactic variant, but even more out-of-place would be colon-doubling to signal "end of keywords":


        foo
                collect:: [:x|x barf]
                select:: [:y|y isKnorz]
                inject: Kiffle into:: [:clomb :blui | clomb baz: blui])
                sum

which is just one stop before Self's syntax, which abuses capitalization (watch for the Into):

        foo
                collect: [:x|x barf]
                select: [:y|y isKnorz]
                inject: Kiffle Into: [:clomb :blui | clomb baz: blui])
                sum

Btw: With higher order messages, it would also look quite good:


        (foo
                collect barf
                select isKnorz
                "inject: Kiffle into: [:clomb :blui | clomb baz: blui]" "<-- not sure here, tho"
                inject Kiffle
                        into baz: blui)
                sum

TL;DR: the ..:then..: messages have an important role in readability, so should we abandon them, we need something else, maybe even richer syntax.

Best regards
        -Tobias



[1]: With that, I mean, you can't forward-progam here. Think you star with some collection and inspect it. Then you go back to your do it,
#collect: on it and inspect again. But then, to do the same with another, eg, #select:, first you have to put parenthesis around it, to then go to the end again and add your code. Repeat.








-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20190911/abee7cc6/attachment.html>


More information about the Squeak-dev mailing list