[Cuis-dev] Methods that return multiple values

rabbit rabbit at callistohouse.org
Thu Jun 22 13:21:01 PDT 2023


Hey! I got inspired by your proposal, Luciano, and here's my solution in eventual promises. Code can be loaded as:

> Installer ss project: 'Cryptography'; install: 'ProCrypto.release.3'.

I added a test method

> RefsTest>>#testMultiReturns
>
> | selectCount unionFlag pair |
> unionFlag := false.
> selectCount := 0.
> ((pair := self promiseResolverPair) key xgcd: 9)
> <<* [:each | selectCount := selectCount + 1. Transcript cr; show: 'each = ', each];
> <<* [:g :s :t | unionFlag := true. Transcript cr; show: 'g = ', g, '; s = ', s, '; t = ', t. g + s + t].
> pair value resolve: 21.
> (Delay forMilliseconds: 333) wait.
> self assert: (selectCount == 3).
> self assert: (unionFlag).

This calls new multireturn #xgcd: method

> xgcd: anInteger
> " 21 xgcd: 9"
> | g s t |
> g := self gcd: anInteger.
> s := self / g.
> t := anInteger / g.
> ^ { g. s. t}

And in the test method there are eventual sends (#<<*) to the promise of the #xgcd: send once the reciever promise is resolved to 21. This implementation detects cardinality of the continuation block and sends #whenResolved: appropriately, for future evaluation.

> Object>>#<<* continuation
>
> (continuation numArgs == 1)
> ifTrue: [^ self whenResolved: [:result | result do: [:each | continuation value: each]]].
> ^ self whenResolved: [:result | continuation valueWithArguments: result].

One can see a 1 cardinality schedules the continuation to evaluate with each result, while a continuation with cardinality 2 or more will be scheduled to receive all results. #valueWithArguments:

Here are 2 return handlers,

> promise := ((pair := self promiseResolverPair) key xgcd: 9).

the first for each argument

> promise <<* [:each | selectCount := selectCount + 1. Transcript cr; show: 'each = ', each];

and the second for all three arguments.

> promise <<* [:g :s :t | unionFlag := true. Transcript cr; show: 'g = ', g, '; s = ', s, '; t = ', t. g + s + t].

--
❤️‍🔥🐰

On 6/21/23 09:44, Luciano Notarfrancesco via Cuis-dev wrote:

> Interesting, thanks for sharing!
> Actually I think it’s the same thing I did, my implementation calls BlockClosure>>#valueWithPossibleArgs: and takes only as many arguments as needed by the block but the array can be bigger than that (it should be named #valueWithPossibleArguments: tho, abbreviations are ugly).
>
> On Wed, 21 Jun 2023 at 15:37 Christian Haider via Cuis-dev <cuis-dev at lists.cuis.st> wrote:
>
>> I added something similar to my Values package (VW and ports).
>>
>> The source is
>>
>> SequenceableCollection>>asArgumentsIn: aBlock
>>
>> "Evaluate aBlock with the receiver's elements as parameters.
>>
>> aBlock takes its arguments from the receiver.
>>
>> 'ok'
>>
>> #(1 2 3) asArgumentsIn: [:a :b :c | a + b + c]
>>
>> #(1 2 3) asArgumentsIn: [:a :b | a + b]
>>
>> #(1 2 3) asArgumentsIn: [:a | a]
>>
>> #(1 2 3) asArgumentsIn: [42]
>>
>> 'not ok'
>>
>> #(1 2 3) asArgumentsIn: [:a :b :c :d | a + b + c + d]
>>
>> "
>>
>> ^aBlock cullWithArguments: self asArray
>>
>> The difference is that it takes a list of any size and picks out the first items and binds them to the variables.
>>
>> I use it often for CSV processing like
>>
>> (line tokensBasedOn: $;) asArgumentsIn: [:first :second :y | … ].
>>
>> I am just a bit unhappy with the name – it is too long. It reads ok though.
>>
>> The pipe character is an interesting idea. I have to think about it.
>>
>> I am use it for a while now and I am very happy with it.
>>
>> Happy hacking,
>>
>> Christian
>>
>> Von: Cuis-dev <cuis-dev-bounces at lists.cuis.st> Im Auftrag von Luciano Notarfrancesco via Cuis-dev
>> Gesendet: Mittwoch, 21. Juni 2023 15:13
>> An: Discussion of Cuis Smalltalk <cuis-dev at lists.cuis.st>
>> Cc: Luciano Notarfrancesco <luchiano at gmail.com>
>> Betreff: [Cuis-dev] Methods that return multiple values
>>
>> Smalltalk doesn’t have a convention for methods returning multiple values, and I’m not aware of any implementation.
>>
>> An example of such thing is the extended gcd: ‘a xgcd: b’ returns g, s, t where g is the gcd, and as + bt = g. Writing methods that return multiple values is easy with the curly brackets syntax, Integer>>#xgcd: ends with something like
>>
>> ^ {g. s. t}
>>
>> But using sending messages that return multiple values is kind of annoying, I end up doing something like:
>>
>> xgcd := a xgcd: b.
>>
>> g := xgcd at: 1.
>>
>> s := xgcd at: 2.
>>
>> t := xgcd at: 3
>>
>> Some years ago I thought about using blocks for this, but I never tried it. Today I just did a little experiment implementing anArray | aBlock as ‘^ aBlock valueWithPossibleArgs: self’ and I can do:
>>
>> (a xgcd: b) | [:g :s :t| … ]
>>
>> This is seems quite nice already, I guess I’ll start using it and see how it feels. But the point of this mail is not to show a solution, but to ask if anyone have thought about this or if they know any nicer solutions. Any ideas?
>>
>> --
>> Cuis-dev mailing list
>> Cuis-dev at lists.cuis.st
>> https://lists.cuis.st/mailman/listinfo/cuis-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20230622/6af3c04a/attachment.htm>


More information about the Cuis-dev mailing list