Hi Paul,

1. I am a bit worried about the dual use of literal map syntax and
   object decomposition in Groovy:
    1. In the "def sum(xs) ..." example xs is list (of Number|s), and
       "case []" is the branch that handles an empty list.
    2. Whereas in the "switch (event) ..." example the " case [type:
       'click', ...]" branch does not compare to a map, but
       decompositions the event object into its type, etc parts.
    3. While seeing any object in Groovy as a map of properties has
       been around forever,  it does already clash with peoples'
       expectations sometimes when the object /is /a Map (violating
       least surprise).
    4. So I was wondering if introducing a seperate syntax for object
       decomposition which sets it apart from literal map syntax would
       make sense... ?
2. In "case [type: 'click',  x: var x, y: var y]" the "x: var x" parts
   looks unnecsessarily verbose/Java-ish to me - can/should we allow
   just "x" here, i.e. "case [ type: 'click',  x, y ] -> handleClick(x, y)"
    1. Or, in case a mapping shall occur, can we drop the "var",
       i.e. "case [ type: 'click', widthPos:x, heightPos:y ] ->
       handleClick(x, y)"
        1. (This might tie in with my suggestion above: This might
           only work if there is an explicit syntax for a decomposition
           pattern that does not  look like a map literal.)

Cheers,
mg

def sum(xs) {
        switch (xs) {
            case []                -> 0
            case [var h, var... t] -> h + sum(t)
        }
    }

 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()
    }



Am 27.04.2026 um 13:39 schrieb Paul King:
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