Re: features for groovy-6.0.0-alpha-1
MG <mgbiz-yvYIh6MZAuFWk0Htik3J/[email protected]> Thu, 30 Apr 2026 18:40:45 +0200
| Newsgroups | gmane.comp.lang.groovy.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Jochen,
1. @GPars features: I had just started writing a similar response,
along the line of having an annotation that could "auto parallel"
code...
1. General question: Is there a specific reason that we do not do
auto-parallelization in general, similar in spirit to e.g.
Java's BigDecimal implementation that heuristically picks
different algorithms for multiplication under the hood, based on
the size of the numbers in play ?
2. @collectParallel:
1. I prefer urls.parallel over urls.parallel(), due to it being
less verbose & parallel not changing anything in urls or being
expensive, but just being a tag or marker that influences
behavior in the call chain.
2. parallel(urls).collect would imho be even better, but since it
would need to be a static method it is alas inconvenient with
regards to Intellisense/autocompletion.
3. Also fo Intellisense reasons I think collectParallel is overall
better than parallelCollect.
Cheers,
mg
Am 30.04.2026 um 17:36 schrieb Jochen Theodorou:
> actually one question regarding GPars features.
>
> Afaik you could do urls.collectParallel{...}, but also
> urls.parallel.collect{...}.
>
> I guess it was excluded because of getParallel() as "Legacy JSR-166
> ParallelArray API; obsolete since Java 8 streams"
>
> But I see this more as a DSL choice, then depending on a feature. I
> personally like urls.parallel().collect most, then
> urls.parallel.collect and only on last place urls.collectParallel.
> Frankly I would have even expected urls.parallelCollect, if I had seen
> it for the first time.
>
> To be more specific.. assume you have
>
> def findOkUrls(urls) {
> urls.collect { fetch(it) }
> .findAll { it.status == 200 }
> .groupBy { it.host }
> }
> findOkUrls(myUrls)
>
> and then you could replace that with
>
> def findOkUrls(urls) {
> urls.collect { fetch(it) }
> .findAll { it.status == 200 }
> .groupBy { it.host }
> }
>
> ParallelScope.withPool(Pool.cpu()) {
> findOkUrls(myUrls)
> }
>
> Meaning not touching the method itself.
>
> bye Jochen
>
> On 4/30/26 05:37, Paul King wrote:
>> I have merged the GPars-related functionality. I'll tidy the docs but
>> shout if you spot any problems.
>>
>> Cheers, Paul.
>>
>> On Mon, Apr 27, 2026 at 9:39 PM Paul King <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> Hi folks,
>>
>> I believe the following features are ready for inclusion in Groovy
>> 6.0.0-alpha-1.
>> Please see the relevant PRs and Jira issues for more information.
>>
>> Feedback, as always, is welcome.
>>
>> Cheers, Paul.
>>
>> GEP-18 -- Ported GPars features
>> ================================
>>
>> 1. Parallel collections inside a scope -- drop-in speedup
>>
>> ParallelScope.withPool(Pool.cpu()) {
>> urls.collectParallel { fetch(it) }
>> .findAllParallel { it.status == 200 }
>> .groupByParallel { it.host }
>> }
>>
>> Familiar GPars xxxParallel names, pool-isolated and
>> virtual-thread-ready.
>>
>> 2. Dataflows -- orchestration by data dependency, not thread
>> choreography
>>
>> def df = new Dataflows()
>> async { df.result = combine(df.user, df.prefs) }
>> async { df.user = loadUser(id) }
>> async { df.prefs = loadPrefs(id) }
>> println await(df.result)
>>
>> The order in source is irrelevant; readers block until the
>> writers bind. Reads as plainly as sequential code.
>>
>> But also, actors/active objects, agents and channels.
>>
>> GEP-20 -- Additional multi-assignment forms
>> ============================================
>>
>> 1. Tail rest against a Stream -- head/body split with no
>> materialisation
>>
>> Files.lines(path).withCloseable { src ->
>> def (header, *body) = src
>> body.filter { !it.isBlank() }.forEach { process(it) }
>> }
>>
>> Path A keeps the Stream lazy and propagates onClose -- the
>> killer demo for the streaming contract.
>>
>> 2. Head and middle rest -- edge-aware slicing in one line
>>
>> def (first, *middle, last) = readings // peel both ends
>> def (l, *m, r) = segment // boundary + interior
>>
>> Replaces [0] / [1..-2] / [-1] boilerplate that's surprisingly
>> common.
>>
>> 3. Map-style destructuring -- beans and config in one shot
>>
>> def (host: h, port: p, name: n) = config
>> def (name: String fullName, age: int a) = person
>>
>> Works against Map, beans, and GroovyObject uniformly via the
>> MOP -- the rename form (name: fullName) is a quiet bonus.
>>
>>
>> When assessing GEP-20, bear in mind the very early draft for GEP-19
>> targetted tentatively for Groovy 7.
>>
>> GEP-19 -- Structural pattern matching in switch
>> ================================================
>>
>> 1. Recursive list algorithm in its canonical functional shape
>>
>> def sum(xs) {
>> switch (xs) {
>> case [] -> 0
>> case [var h, var... t] -> h + sum(t)
>> }
>> }
>>
>> The motivating example -- what you can't write tidily today.
>>
>> 2. Map patterns for tagged-shape dispatch (events, JSON, configs)
>>
>> switch (event) {
>> case [type: 'click', x: var x, y: var y] ->
>> handleClick(x, y)
>> case [type: 'key', code: var k] -> handleKey(k)
>> case [type: 'scroll', ...] -> redraw()
>> }
>>
>> Open semantics plus rest binding makes this read like a
>> protocol spec.
>>
>> 3. Type pattern + record pattern + guard -- visitor replacement
>>
>> switch (shape) {
>> case Circle c when c.radius > 0 -> Math.PI * c.radius**2
>> case Rect(int w, int h) -> w * h
>> case Line(_, Point p2) -> "ends at $p2"
>> default -> 0
>> }
>>
>> One construct subsumes instanceof chains, accessor calls, and
>> the constraint check.
>>
>