[ 
https://issues.apache.org/jira/browse/GROOVY-11492?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18133191#comment-18133191
 ] 

ASF GitHub Bot commented on GROOVY-11492:
-----------------------------------------

paulk-asert commented on PR #3054:
URL: https://github.com/apache/groovy/pull/3054#issuecomment-6451570311

   AI read:
   
   > Thanks Eric, I think the direction is promising. The predicate gating on 
`type.dim0()` holds up in practice. Untyped declarations, `Object o = {}`, and 
closures with params, `->`, `;` or labels all stay closures, so the change only 
kicks in where it should. For non-closure element types it's a clear win:
   > 
   > | Code | master | PR |
   > |---|---|---|
   > | `String[] a = {}` | 1-element array holding the closure | `[]` |
   > | `Boolean[] a = { false }` | `[true]` (closure → asBoolean) | `[false]` |
   > | `final int[] a = {1}`, `int[] a = {1,}`, `Object[] a = {1, 2}` | fail | 
work |
   > | `@CompileStatic String[] s = { 'a' }` | STC error | works |
   > 
   > The friction is where the element type can accept a closure, i.e. the 
GROOVY-8561 territory from 2018 (PR 691 didn't get the three +1s back then). 
Here are the edge cases I found, all run against your branch:
   > 
   > **Behaviour changes for Closure/SAM/Object element types**
   > 
   > | Code | master | PR |
   > |---|---|---|
   > | `Closure[] a = {}` | `[Closure]` | `[]` |
   > | `def m(Closure[] cs = {})` | `[Closure]` | `[]` |
   > | `Object[] o = {}` | `[Closure]` | `[]` |
   > | `Closure[] a = { 1 }` | `[Closure]` | runtime failure |
   > | `Closure[] a = { it }` | `[Closure]` | runtime failure (no `it`) |
   > | `String[] s = { it }` | 1-element array holding the closure | runtime 
failure |
   > | `Runnable[] r = { println 'x' }` | `[Closure]` | compile error (command 
chain not allowed in array initializer) |
   > | `Closure[] a = { println('x') }` | `[Closure]` | **prints `x` at 
declaration time and stores `[null]`** |
   > 
   > The last one worries me most because it changes behaviour silently. Any 
`Closure[]`/`Runnable[]`/`Callable[]` declaration whose single body expression 
isn't a command chain now runs eagerly, and its result (often `null`) passes 
the cast.
   > 
   > **Body shape decides the meaning.** `Closure[] a = { it }` is an array but 
`{ it -> it }` is a closure. `String[] s = { 'a' }` is an array but `{ 'a'; 'b' 
}` and `{ 'a' }.call()` are closures. It's consistent with the grammar, but 
hard to explain to users.
   > 
   > **Nested braces crash the parser.** `Object[] o = { {} }` and `Closure[] 
cs = { {}, {} }` fail with "General error during parsing: Cannot invoke 
ClassNode.makeArray() because base is null". This already happens on master 
with the long form (`new Object[]{{}}`), see the `//if (subType == null) 
produce closure or throw exception` TODO in `visitArrayInitializer`. Your 
branch just makes it much easier to hit. It also blocks the escape hatch 8561 
documented (`Closure[] fns = { { } }`). Taking the "produce closure" branch of 
that TODO would fix the crash and restore the escape hatch.
   > 
   > **Other bits**
   > - Only a single declarator is handled: `int[] a = {1}, b = {2}` (valid 
Java) falls through to the closure path and fails at runtime with a cast error.
   > - `def m( {` now reports the missing `)` at line 2 col 2 instead of at the 
`{` (line 1 col 8). That comes from the `formalParameter` restructuring.
   > - `String[] a = { ['a', 'b'] }` gives `["[a, b]"]` (length 1, element is a 
`String`) in both dynamic and `@CompileStatic`: the list is coerced via 
toString. The long form `new String[]{ ['a','b'] }` does exactly that on master 
too, so it isn't new, but the terse form makes it easier to write, and Java 
would reject it.
   > 
   > **Possible paths forward**
   > - **A. Keep the current semantics (Java-faithful).** This has the simplest 
rule but is a breaking change for Closure/SAM/Object arrays, including the 
silent eager-evaluation case. We'd need a dev-list decision (given the 8561 
precedent), a COMPATIBILITY note, and ideally a compile-time diagnostic when a 
Closure/SAM-typed array element isn't a closure/lambda/method ref. That 
diagnostic can't be exact in dynamic code, e.g. `{ getHandler() }` is 
legitimate.
   > - **B. Type-aware fallback (my preference).** Use the array reading, 
except when the initializer is empty or has a single element *and* the leaf 
component type is `Closure`, a SAM type, or (TBD) `Object`. In that case keep 
today's closure promotion. Multi-element and nested initializers would always 
be arrays. Nothing that works today breaks, and Java users get the forms they 
actually paste (`String[]`, `int[]`, `int[][]`, …). The catch is that SAM-ness 
is only known after resolution. AstBuilder could build both readings for the 
empty/single-element shapes and pick one post-resolution. I'm not sure where 
that hook best lives, and I'm curious what you think.
   > - **C. Only shapes no closure body can parse as.** Treat the braces as an 
array only when there's a top-level comma or nested braces. It's cheap and 
non-breaking, but `String[] s = {}`, probably the most common pasted Java 
idiom, would keep today's odd result, so it doesn't really meet the ticket's 
goal.
   > 
   > Whichever way we go, fixing the nested-brace NPE seems worthwhile on its 
own, since it's a crash on master today. Tests pinning down the chosen 
semantics for `{}`, `{ it }`, `{ -> }`, `{ { } }`, `Runnable[] r = { … }` and 
`Object[] o = {}` would also help.




> Java compatibility: array initializers without "new Type[]"
> -----------------------------------------------------------
>
>                 Key: GROOVY-11492
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11492
>             Project: Groovy
>          Issue Type: Improvement
>          Components: parser-antlr4
>            Reporter: Eric Milles
>            Assignee: Eric Milles
>            Priority: Major
>              Labels: arrays
>
> There are a few cases where bare array initializers are not yet supported:
> # {{int[][] array = \{ \{1,2\}, \{3,4\} \};}}
> # {{@Target(\{ ElementType.FIELD, ElementType.METHOD \})}}
> # {code:groovy}@interface A {
>   String[] strings() default {}
> }
> {code}
> These were implemented as part of [1] but the PR was closed.  It may be worth 
> looking back over what was done and re-implementing one or more of these 
> cases.  It was noted that {{Closure[] array = \{\};}} is one of the edge 
> cases that leads to ambiguity.
> [1] https://github.com/apache/groovy/pull/691



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to