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.
>>
>