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.


Reply via email to