groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Paul King <pa...@asert.com.au>
Subject Re: [Poll] About supporting Java-like array
Date Sun, 29 Apr 2018 13:29:30 GMT
+1

For completeness, I added some more details about the breaking changes and
workarounds into the issue - included below for easy reading.

Cheers, Paul.

=================

Groovy currently "promotes" a singleton instance of an object into an array
for assignments, e.g.:

Integer[] nums = 42
assert nums instanceof Integer[]
assert nums.size() == 1
assert nums[0] instanceof Integer

This aligns with how Groovy behaves if you try to call `.each{}` on a
non-aggregate. It treats it like a singleton collection and "iterates" over
the one item.

The existing behavior also currently works for singleton Closures:

Closure[] fns0 = { }
assert fns0 instanceof Closure[]
assert fns0.size() == 1
assert fns0[0] instanceof Closure

To add support for Java array notation, we will need to partially disable
this behavior. The proposed change involves smart parsing, e.g. it will
distinguish cases which must be an array and cases which must be a closure
but there are some degenerate edge cases which will become breaking changes.

The case with the empty closure above will no longer work, instead you will
get this behavior, i.e. an empty array is given precedence over an empty
closure:

Closure[] fns1 = { }
assert fns1 instanceof Closure[]
assert fns1.size() == 0

To get the old behavior back you have a couple of options. Firstly, you can
provide the explicit closure argument delimiter:

Closure[] fns2 = { -> } // can't be an array
assert fns2 instanceof Closure[]
assert fns2.size() == 1
assert fns2[0] instanceof Closure

Or don't rely on singleton promotion and explicitly provide also the array
curly braces:

Closure[] fns3 = { { } }
assert fns3 instanceof Closure[]
assert fns3.size() == 1
assert fns3[0] instanceof Closure

Similarly, for the case of the identity closure:

Closure[] fns4 = { it }

Previously this worked but under this proposal will give:

groovy.lang.MissingPropertyException: No such property: it ...

Your options are to add the extra array braces as per above, or use
explicit params, e.g.:

Closure[] fns5 = { it -> it }
assert fns5 instanceof Closure[]
assert fns5.size() == 1
assert fns5[0] instanceof Closure

Alternatively, for this special case you have the following additional
option:

Closure[] fns6 = Closure.IDENTITY
assert fns6 instanceof Closure[]
assert fns6.size() == 1
assert fns6[0] instanceof Closure

There are other cases as well, e.g. this code which currently creates a
closure array containing a closure returning the integer 0:

Closure[] fns7 = { 0 }

will no longer be supported and will fail with:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast
object '0' with class 'java.lang.Integer' to class 'groovy.lang.Closure'
The solutions are similar to previously (explicit delimiter):

Closure[] fns8 = { -> 0 }

or (explicit outer array braces):

Closure[] fns9 = { { 0 } }


On Sun, Apr 29, 2018 at 8:37 PM, Daniel.Sun <sunlan@apache.org> wrote:

> Hi all,
>
>      As we all know, Java array is one of features widely applied in Java
> projects. In order to improve the compatibility with Java(Copy & Paste).
> The
> PR[1] will make Groovy support java-like array and make the differences[2]
> with Java less and less, e.g.
>
> *One-Dimensional array*
> ```
> String[] names = {'Jochen', 'Paul', 'Daniel'}
> ```
>
> *Two-Dimensional array*
> ```
> int[][] data = {
>     {1, 2, 3},
>     {4, 5, 6},
>     {7, 8, 9},
>     new int[] { 10, 11, 12 },
>     {13, 14, 15}
> }
> ```
>
> *Annotation array*
> ```
> @PropertySources({
>     @PropertySource("classpath:1.properties"),
>     @PropertySource("file:2.properties")
> })
> public class Controller {}
> ```
>
> *More examples*
> Please see the examples on the PR page[1]
>
> *Known breaking changes*
> 1. Closure array in the dynamic mode
> Before
> ```
> Closure[] y = { {-> 1 + 1 } }
> assert y[0].call().call() == 2
> ```
> After
> ```
> Closure[] y = { {-> 1 + 1 } }
> assert y[0].call() == 2
> ```
> 2. String array in the dynamic mode
> Before
> ```
> String[] a = {}
> assert 1 == a.length
> assert a[0].contains('closure')
> ```
> After
> ```
> String[] a = {}
> assert 0 == a.length
> ```
>
>
>       If Groovy 3 supports Java-like array, what do you think about the new
> feature? Do you like it? We need your feedback. Thanks in advance!
>
> [+1] I like it
> [ 0] Not bad
> [-1] I don't like it, because...
>
> Cheers,
> Daniel.Sun
> [1] https://github.com/apache/groovy/pull/691
> [2] http://groovy-lang.org/differences.html
>
>
>
>
> --
> Sent from: http://groovy.329449.n5.nabble.com/Groovy-Users-f329450.html
>

Mime
View raw message