Collections/Streams | About enumerating a sequence up to a matching query ...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
Hi all! :-)

Here is an interesting issue that I repeatedly come across when it comes to enumerating a (sequenceable/ordered) collection up to a certain element, while collecting (i.e. mapping) new elements from that collection. It seems rather tedious to express in code, meaning more than 2-3 lines and maybe involving even temporary variables.

Our stream protocol has #upTo:, which works when you know about the specific element you are looking for. It does not work, however, when you just have an indirect query that should match.

Here is an example. From a list of integer numbers, extract all even ones up to (including) 50, then square those numbers.

(1 to: 100)
   select: [:num | num <= 50 and: [num even]]
   thenCollect: [:num | num * num].

A stream-based approach to shorten the predicate using #upTo: could look like this:

((1 to: 100) readStream upTo: 50)
   select: [:num | num even]
   thenCollect: [:num | num * num].

Now imagine that, unfortunately, we don't know about "50" but only a query, say "a number that is squared 2500". Since #upTo: cannot do that and I do not want to jump collection-stream-collection for this issue, the non-stream approach could look like this:

(1 to: 100)
   select: [:num | (num * num <= 2500) and: [num even]]
   thenCollect: [:num | num * num].

Yet, this is still not my actual issue. What if that collection is not ordered at all but only has a stable sequence? Then we would need to mark the specific element and then reject every element that comes after that. (Note that we replaced #<= with #= to indicate "sequence" instead of "order".)

| found |
found := false.
(1 to: 100)
   select: [:num |
      found := found or: [num * num = 2500].
      found not and: [num even]]
   thenCollect: [:num | num * num].

Uh oh! We just skipped the stop element itself. What if we want to include it? Maybe like this:

| found |
found := false.
(1 to: 100)
   select: [:num | | firstMatch |
      firstMatch := found not and: [num * num = 2500].
      found := found | firstMatch.
      found not | firstMatch and: [num even]]
   thenCollect: [:num | num * num].

Now this looks like a rather complicated implementation for a simple query. Let me give you a last approach using the infamous #valueWithExit.

| list stop select collect result |
list := 1 to: 100.
stop := [:num | num * num = 2500].
select := [:num | num even].
collect := [:num | num * num].
result := OrderedCollection new.
[:break |
   list do: [:num |
      (select value: num) ifTrue: [result add: (collect value: num)].
      (stop value: num) ifTrue: [break value]].
] valueWithExit.

Phew. Is there a simpler approach to this problem? I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case.

aButton withAllOwners
   collect: [:morph | morph color]
   until: [:morph | morph isSystemWindow].

(aButton withAllOwners readStream
   upToSatisfying: [:morph | isSystemWindow])
   collect: [:morph | morph color].

Best,
Marcel


Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Nicolas Cellier
First, concerning the inclusion of the matching element, Stream upTo:
has always excluded that element.
VW has introduced through: which is the inclusive variant of upTo:
I notice that we have adopted that semantic in Collection protocol
with copyUpThrough: versus copyUpTo: , but did not implement through:
in Stream...
My advice would be to stick with those semantics as much as possible
to avoid confusion*.

Concerning the usage of a predicate rather than an element, I don't
see an existing method indeed.
It could be something like: ^self first: (self findFirst: predicate),
but that would answer an empty collection when no element matches,
contrary to copyUpTo:... The handling of zero makes it mandatory to
use periphrases (and temps).
I see that we lack a findFirst:ifNone:...
Of course, if you want then to collect:, then it would cost an
intermediate collection creation and two scans. The alternative would
be to use lazy proxies like in Xtreams, selecting: instead of select,
collecting: instead of collect:... By the way, there is already the
vocable limiting: in Xtreams, that must be fed with a position, but
findFirst: is not yet implemented (Xtreams are not necessarily
positionable).
Maybe we should inquire what clojure and the like have to propose in
this domain for some refreshing ideas...
https://clojuredocs.org/clojure.core/for

*side note: there's already some level of confusion between dialects.
For example, upTo: is not inclusive, but leave the stream position
AFTER the matching element.
    'abcdeh' readStream upTo: $c; next -> $d
But that's not necessarily the case with upToAll:
    'abcdeh' readStream upToAll: 'cd'; next -> $e in Squeak
    'abcdeh' readStream upToAll: 'cd'; next -> $c in VW

Le lun. 8 mars 2021 à 10:43, Marcel Taeumel <[hidden email]> a écrit :

>
> Hi all! :-)
>
> Here is an interesting issue that I repeatedly come across when it comes to enumerating a (sequenceable/ordered) collection up to a certain element, while collecting (i.e. mapping) new elements from that collection. It seems rather tedious to express in code, meaning more than 2-3 lines and maybe involving even temporary variables.
>
> Our stream protocol has #upTo:, which works when you know about the specific element you are looking for. It does not work, however, when you just have an indirect query that should match.
>
> Here is an example. From a list of integer numbers, extract all even ones up to (including) 50, then square those numbers.
>
> (1 to: 100)
>    select: [:num | num <= 50 and: [num even]]
>    thenCollect: [:num | num * num].
>
> A stream-based approach to shorten the predicate using #upTo: could look like this:
>
> ((1 to: 100) readStream upTo: 50)
>    select: [:num | num even]
>    thenCollect: [:num | num * num].
>
> Now imagine that, unfortunately, we don't know about "50" but only a query, say "a number that is squared 2500". Since #upTo: cannot do that and I do not want to jump collection-stream-collection for this issue, the non-stream approach could look like this:
>
> (1 to: 100)
>    select: [:num | (num * num <= 2500) and: [num even]]
>    thenCollect: [:num | num * num].
>
> Yet, this is still not my actual issue. What if that collection is not ordered at all but only has a stable sequence? Then we would need to mark the specific element and then reject every element that comes after that. (Note that we replaced #<= with #= to indicate "sequence" instead of "order".)
>
> | found |
> found := false.
> (1 to: 100)
>    select: [:num |
>       found := found or: [num * num = 2500].
>       found not and: [num even]]
>    thenCollect: [:num | num * num].
>
> Uh oh! We just skipped the stop element itself. What if we want to include it? Maybe like this:
>
> | found |
> found := false.
> (1 to: 100)
>    select: [:num | | firstMatch |
>       firstMatch := found not and: [num * num = 2500].
>       found := found | firstMatch.
>       found not | firstMatch and: [num even]]
>    thenCollect: [:num | num * num].
>
> Now this looks like a rather complicated implementation for a simple query. Let me give you a last approach using the infamous #valueWithExit.
>
> | list stop select collect result |
> list := 1 to: 100.
> stop := [:num | num * num = 2500].
> select := [:num | num even].
> collect := [:num | num * num].
> result := OrderedCollection new.
> [:break |
>    list do: [:num |
>       (select value: num) ifTrue: [result add: (collect value: num)].
>       (stop value: num) ifTrue: [break value]].
> ] valueWithExit.
>
> Phew. Is there a simpler approach to this problem? I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>
> (aButton withAllOwners readStream
>    upToSatisfying: [:morph | isSystemWindow])
>    collect: [:morph | morph color].
>
> Best,
> Marcel
>

Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Jaromir Matas
In reply to this post by marcel.taeumel
How about this, using valueWithExit again (still long but a bit more
readable):

| result supplier |
supplier := (1 to: 100) readStream.
result := OrderedCollection new.

[:exitBlock |
  [supplier atEnd]
    whileFalse: [ | value |
      value := supplier next.
      value even ifTrue: [result add: value squared].
      value squared = 2500 ifTrue: [exitBlock value]]
] valueWithExit.
result



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Jaromir Matas
In reply to this post by Nicolas Cellier
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Nicolas Cellier
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Nicolas Cellier
Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
> And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols.

It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part.

I do like the verbs and the prepositions, just not the order of keywords

Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example:

Array streamContents: [:result |
   aButton withAllOwners
      upThrough: [:morph| morph isSystemWindow]
      do: [:morph | result nextPut: morph color]].

Best,
Marcel

Am 09.03.2021 14:15:33 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

Maybe #upThrough:do: would work? Here is an example:


Definitively better than #do:upThrough:. :-)

Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ...

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 14:34:21
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
> And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols.

It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part.

I do like the verbs and the prepositions, just not the order of keywords

Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example:

Array streamContents: [:result |
   aButton withAllOwners
      upThrough: [:morph| morph isSystemWindow]
      do: [:morph | result nextPut: morph color]].

Best,
Marcel

Am 09.03.2021 14:15:33 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
Thus my proposal to reuse the verb "select" [...]

Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object.  And so should #upThrough:. Hmpf. 

#selectUpThrough:thenDo:
#selectUpTo:thenDo:

Bah. This is so wordy. -.-"

Best,
Marcel

Am 09.03.2021 14:52:00 schrieb Thiede, Christoph <[hidden email]>:

Maybe #upThrough:do: would work? Here is an example:


Definitively better than #do:upThrough:. :-)

Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ...

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 14:34:21
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
> And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols.

It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part.

I do like the verbs and the prepositions, just not the order of keywords

Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example:

Array streamContents: [:result |
   aButton withAllOwners
      upThrough: [:morph| morph isSystemWindow]
      do: [:morph | result nextPut: morph color]].

Best,
Marcel

Am 09.03.2021 14:15:33 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

marcel.taeumel
Maybe I will just do this from now on:

aButton withAllOwners in: [:list |
(list first: (list
findFirst: [:m | m isSystemWindow]))
collect: [:m | m color]]

Best,
Marcel

Am 09.03.2021 15:01:51 schrieb Marcel Taeumel <[hidden email]>:

Thus my proposal to reuse the verb "select" [...]

Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object.  And so should #upThrough:. Hmpf. 

#selectUpThrough:thenDo:
#selectUpTo:thenDo:

Bah. This is so wordy. -.-"

Best,
Marcel

Am 09.03.2021 14:52:00 schrieb Thiede, Christoph <[hidden email]>:

Maybe #upThrough:do: would work? Here is an example:


Definitively better than #do:upThrough:. :-)

Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ...

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 14:34:21
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
> And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols.

It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part.

I do like the verbs and the prepositions, just not the order of keywords

Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example:

Array streamContents: [:result |
   aButton withAllOwners
      upThrough: [:morph| morph isSystemWindow]
      do: [:morph | result nextPut: morph color]].

Best,
Marcel

Am 09.03.2021 14:15:33 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

Hmm... maybe "detect" is what we could re-use as a word?


"detect" is already being abused today IMO. I don't like #detect(Max|Min|Sum): because my general understanding of detection is to iterate until something specific is found.


Or go the Python way (probably also used in other languages?) and support multiple semantics of the "upTo:"/"upThrough:" argument in the same selector. So both would work:


#(1 2 3) upTo: 2.

#(1 2 3) upTo: [:x | x isEven].


But I don't like this approach myself, because what should this one return then?


#(notEven even maybeEven) upTo: #isEven.


So I would be fine with #selectUpTo:thenDo: ...


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 15:06:34
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Maybe I will just do this from now on:

aButton withAllOwners in: [:list |
(list first: (list
findFirst: [:m | m isSystemWindow]))
collect: [:m | m color]]

Best,
Marcel

Am 09.03.2021 15:01:51 schrieb Marcel Taeumel <[hidden email]>:

Thus my proposal to reuse the verb "select" [...]

Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object.  And so should #upThrough:. Hmpf. 

#selectUpThrough:thenDo:
#selectUpTo:thenDo:

Bah. This is so wordy. -.-"

Best,
Marcel

Am 09.03.2021 14:52:00 schrieb Thiede, Christoph <[hidden email]>:

Maybe #upThrough:do: would work? Here is an example:


Definitively better than #do:upThrough:. :-)

Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ...

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 14:34:21
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
> And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols.

It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part.

I do like the verbs and the prepositions, just not the order of keywords

Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example:

Array streamContents: [:result |
   aButton withAllOwners
      upThrough: [:morph| morph isSystemWindow]
      do: [:morph | result nextPut: morph color]].

Best,
Marcel

Am 09.03.2021 14:15:33 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


maybe I have expressed myself incorrectly, please let me try to correct this:


1. You do not like the name #do:upThrough:.


Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order.
And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols.

2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-)

See below Nicolas' comments on #copyUpThrough:

This one?

My advice would be to stick with those semantics as much as possible to avoid confusion*.

Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-)

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 13:39:17
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi Christoph,

let me try to summarize your thoughts:

1. You do not like the name #do:upThrough:.
2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol.

Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer

Best,
Marcel

Am 09.03.2021 13:23:16 schrieb Thiede, Christoph <[hidden email]>:

Hi Marcel,


I would pay additional attention to the order of arguments. :-)


#do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it?

What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs?

In the following assuming that the right answer is zero ...:


I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods.


What do you think? :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 9. März 2021 09:40:38
An: squeak-dev
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
Hi all.

I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".)

I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable.

Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks.

Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-)

***

All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us.

Then, my example use from the beginning could look like this:

Array streamContents: [:result |
   aButton withAllOwners
      do: [:morph | result nextPut: morph color]
      upThrough: [:morph | morph isSystemWindow]].

Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe.

What do you think?

Best,
Marcel

Am 09.03.2021 08:07:23 schrieb Nicolas Cellier <[hidden email]>:

Also the question of inclusion will arise as well as the order of predicates...

There could also be symetrical once: [:x | x > 10].

Le lun. 8 mars 2021 à 23:33, Nicolas Cellier <[hidden email]> a écrit :
I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams.

Le lun. 8 mars 2021 à 21:38, Jaromir Matas <[hidden email]> a écrit :
> I am looking for something like #collect:until: or #upToSatisfying:. I do
want the stop element to be included here, not sure about the general case.
>
> aButton withAllOwners
>    collect: [:morph | morph color]
>    until: [:morph | morph isSystemWindow].
>

Hi again, ahh so you're actually looking for a generalized collect for any
SequencableCollection or Stream :) Like this?

(1 to: 100)
        collect: [:x | x squared]
        where: [:x | x even]
        until: [:x | x squared = 2500]


collect: collectBlock where: whereBlock until: untilBlock

        | result supplier |
        supplier := self readStream.
        result := {} writeStream.
        [[supplier atEnd]
            whileFalse: [ | val |
              val := supplier next.
              (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value:
val)].
              (untilBlock value: val) ifTrue: [^result contents]]
        ] value.
        ^result contents

collect: colBlock until: untilBlock

        ^self collect: colBlock where: [:each | true] until: untilBlock

or even:

collect: colBlock

        ^self collect: colBlock until: [:each | true]




-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Jaromir Matas
In reply to this post by marcel.taeumel
To add my 2¢; how about, in the spirit of the pidgin English tradition:

        aCollection
                collect: [:x | x squared]
                selecting: #even
                stopIf: [:x | x squared = 2500]

complemented by:

        aCollection
                collect: [:x | x squared]
                selecting: #even
                stopBefore: #isNil



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

-1 :-)


For the same reason why I argued against #do:upThrough: - the order of arguments would be confusing. We would first check to stop, and then do any collect/select operations.


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Jaromir Matas <[hidden email]>
Gesendet: Donnerstag, 11. März 2021 08:33:38
An: [hidden email]
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
To add my 2¢; how about, in the spirit of the pidgin English tradition:

        aCollection
                collect: [:x | x squared]
                selecting: #even
                stopIf: [:x | x squared = 2500]

complemented by:

        aCollection
                collect: [:x | x squared]
                selecting: #even
                stopBefore: #isNil



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Jaromir Matas
I know what you mean Christoph but I personally prefer to see the main,
substantial action first and the infrequent event/stop condition last. It's
like: "Go this way and do that until your reach a stop sign" ;)



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Christoph Thiede

But this description is not even consistent with the idea of your #collect:selecting:stopBefore:, is it? Or should this method indeed always select at least one element?


Reminds me of the difference between "while...do" and "do...until" loops. :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Jaromir Matas <[hidden email]>
Gesendet: Donnerstag, 11. März 2021 10:58:59
An: [hidden email]
Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...
 
I know what you mean Christoph but I personally prefer to see the main,
substantial action first and the infrequent event/stop condition last. It's
like: "Go this way and do that until your reach a stop sign" ;)



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Collections/Streams | About enumerating a sequence up to a matching query ...

Jaromir Matas

> Reminds me of the difference between "while...do" and "do...until" loops.
> :-)

True, I never know and always have to doublecheck :)

Ok, I'll change the wording:

aCaseOfBeers
    collect: [:each | self drink: each]
    selecting: #lager
    stopBefore: #isMidnight

assuming `self drink` returns the empty bottle ;)



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir