#in: for collections

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

#in: for collections

Bert Freudenberg
On 25.12.2009, at 14:50, Randal L. Schwartz wrote:
>
> #((1 2 true) (2 1 false)) do: [:row |
>   [:a :b :r | "do something useful" ] valueWithArguments: row.
> ].
>
> Beware... if your row doesn't have exactly three values, you'll
> get an exception.  If you don't want that, consider #valueWithPossibleArgs:

I've sometimes wished for a "reversed" valueWithArguments:, because I used it like Randal above, but felt it obfuscates the control flow. Here's one of my usages (1):

        ^[:tpService :tpConn :tpChannels |
                tpChannels collect: [:channel |
                        TelepathyChannel
                                connection: tpConn dbusConnection
                                busName: tpService
                                objectPath: channel dbusPath]
        ] valueWithArguments: sharedActivity getChannels

which looks like it returns a block and makes it hard to follow what happens. It does look nicer than this though (2):

        | args tpService tpConn tpChannels |
        args := sharedActivity getChannels.
        tpService := args first.
        tpConn := args second.
        tpChannels := args third.
        ^tpChannels collect: [:channel |
                        TelepathyChannel
                                connection: tpConn dbusConnection
                                busName: tpService
                                objectPath: channel dbusPath]

But I'd much rather write this (3):

        sharedActivity getChannels in: [:tpService :tpConn :tpChannels |
                tpChannels collect: [:channel |
                        TelepathyChannel
                                connection: tpConn dbusConnection
                                busName: tpService
                                objectPath: channel dbusPath]]

... however, #in: only works with single-argument blocks. Making #in: work with multi-arg blocks is of course possible but feels not right either. Does anybody have an idea for a better selector? Or another idea for how to code  this?

In my example, "#getChannels" is an external library call returning an array, this is the code that converts the raw result into a proper object structure. You can argue that low-level code like this is okay to look like (2) but I'd say it doesn't have to ;)

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Colin Putney

On 2009-12-26, at 3:20 AM, Bert Freudenberg wrote:

> ... however, #in: only works with single-argument blocks. Making #in: work with multi-arg blocks is of course possible but feels not right either. Does anybody have an idea for a better selector? Or another idea for how to code  this?

I've occasionally mused that #do: and #in: ought to be the inverse of each other. Object>>do: would behave like #in: and Collection>>in: would evaluate the block with 'self anyOne' as the parameter. With multi-arg blocks it could supply more elements, as in your third example. On UndefinedObject, both methods would do nothing. This would probably break a lot of code, so it's not really feasible now, but if I could think of some other selectors that made sense...

Your idea here strikes me as similar to Ruby's splat operator, or the way functional languages deal with lists by recursively splitting them into head and tail. It feels like a really useful idiom, and it would be nice to have it in Smalltalk, the same way we have #ifTrue:ifFalse: rather than actual syntax for booleans.

> In my example, "#getChannels" is an external library call returning an array, this is the code that converts the raw result into a proper object structure. You can argue that low-level code like this is okay to look like (2) but I'd say it doesn't have to ;)


My first thought on reading the code was "Why the heck is he passing around arrays like that? Make it an object!" Preaching to the choir, I guess. :-)

Colin


Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Tobias Pape
In reply to this post by Bert Freudenberg
This feels to me like pattern matching in more
functional based programming languages like haskel, isn't it?

So Long,
        -Tobias

Am 2009-12-26 um 12:20 schrieb Bert Freudenberg:
> […] sharedActivity getChannels in: [:tpService :tpConn :tpChannels |
> tpChannels collect: [:channel |
> TelepathyChannel
> connection: tpConn dbusConnection
> busName: tpService
> objectPath: channel dbusPath]]
>
> ... however, #in: only works with single-argument blocks. Making #in: work with multi-arg blocks is of course possible but feels not right either. Does anybody have an idea for a better selector? Or another idea for how to code  this?  […]

Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Randal L. Schwartz
In reply to this post by Bert Freudenberg
>>>>> "Bert" == Bert Freudenberg <[hidden email]> writes:

Bert> ... however, #in: only works with single-argument blocks. Making #in:
Bert> work with multi-arg blocks is of course possible but feels not right
Bert> either. Does anybody have an idea for a better selector? Or another idea
Bert> for how to code this?

paralleling "with:" vs "withAll:" and "add:" vs "addAll:", I'd vote
for the slightly clumsy #allIn: or #inAll:

Collection >> #inAll: aBlock
  aBlock #valueWithPossibleArgs: self

If #valueWithPossibleArgs: requires specifically an Array, there might
need to be one definition for arrays, and another for Collections
that call #asArray.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion

Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Steve Wessels-2
In reply to this post by Colin Putney
"...
My first thought on reading the code was "Why the heck is he passing around arrays like that? Make it an object!"
..."

That's exactly what happened to me too, when reading the code.  In fact I started to (in my head) redesign the class method on the reciebet to just process a new object capturing this behavior.

- Steve

On Dec 26, 2009, at 10:08 AM, Colin Putney <[hidden email]> wrote:


On 2009-12-26, at 3:20 AM, Bert Freudenberg wrote:

... however, #in: only works with single-argument blocks. Making #in: work with multi-arg blocks is of course possible but feels not right either. Does anybody have an idea for a better selector? Or another idea for how to code  this?

I've occasionally mused that #do: and #in: ought to be the inverse of each other. Object>>do: would behave like #in: and Collection>>in: would evaluate the block with 'self anyOne' as the parameter. With multi-arg blocks it could supply more elements, as in your third example. On UndefinedObject, both methods would do nothing. This would probably break a lot of code, so it's not really feasible now, but if I could think of some other selectors that made sense...

Your idea here strikes me as similar to Ruby's splat operator, or the way functional languages deal with lists by recursively splitting them into head and tail. It feels like a really useful idiom, and it would be nice to have it in Smalltalk, the same way we have #ifTrue:ifFalse: rather than actual syntax for booleans.

In my example, "#getChannels" is an external library call returning an array, this is the code that converts the raw result into a proper object structure. You can argue that low-level code like this is okay to look like (2) but I'd say it doesn't have to ;)


My first thought on reading the code was "Why the heck is he passing around arrays like that? Make it an object!" Preaching to the choir, I guess. :-)

Colin




Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Bert Freudenberg
In reply to this post by Colin Putney
On 26.12.2009, at 16:08, Colin Putney wrote:
>
>
>> In my example, "#getChannels" is an external library call returning an array, this is the code that converts the raw result into a proper object structure. You can argue that low-level code like this is okay to look like (2) but I'd say it doesn't have to ;)
>
>
> My first thought on reading the code was "Why the heck is he passing around arrays like that? Make it an object!" Preaching to the choir, I guess. :-)

That objection was precisely the reason I put the paragraph in ;)

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Bert Freudenberg
In reply to this post by Randal L. Schwartz
On 26.12.2009, at 17:27, Randal L. Schwartz wrote:

>
>>>>>> "Bert" == Bert Freudenberg <[hidden email]> writes:
>
> Bert> ... however, #in: only works with single-argument blocks. Making #in:
> Bert> work with multi-arg blocks is of course possible but feels not right
> Bert> either. Does anybody have an idea for a better selector? Or another idea
> Bert> for how to code this?
>
> paralleling "with:" vs "withAll:" and "add:" vs "addAll:", I'd vote
> for the slightly clumsy #allIn: or #inAll:
>
> Collection >> #inAll: aBlock
>  aBlock #valueWithPossibleArgs: self
>
> If #valueWithPossibleArgs: requires specifically an Array, there might
> need to be one definition for arrays, and another for Collections
> that call #asArray.

#allIn: reads quite okay I think (4):

        sharedActivity getChannels allIn: [:tpService :tpConn :tpChannels |
                tpChannels collect: [:channel |
                        TelepathyChannel
                                connection: tpConn dbusConnection
                                busName: tpService
                                objectPath: channel dbusPath]]

Not sure if it's useful enough that we want it though?

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: #in: for collections

Randal L. Schwartz
>>>>> "Bert" == Bert Freudenberg <[hidden email]> writes:

Bert> Not sure if it's useful enough that we want it though?

Heck, #in: is already a Squeakism.  Why not add #allIn: and make it
complete. :)

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion