Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
Warning
titleWarning

This page was created to report about the changes in syntax when we switched to a new parser back in 2004. So some of the points below are not necessarily representative of what Groovy supports nowadays. Please take the notes below with a grain of salt!

Here is a checklist of changes you'll need to make to a Groovy classic codebase to ensure compatibility with the new Groovy JSR syntax.

Safe navigation

In Classic Groovy we used to use this syntax

Code Block
class Person = { String name }
y = null
println "${y->name}"    // -> was the optional gpath operator with Classic Groovy syntax

Instead of using the arrow operator for safe navigation to avoid NullPointerException, we're now using the ?. operator

Now in the JSR we use this syntax

Code Block
class Person = { String name }
def y = null
println "${y?.name}"    // Now, ?. is the optional gpath operator the new Groovy JSR

Parameter separator in the closure syntax

This allows us to use one single token for the separator between the closure in Classic Groovy we used to use this syntax

Code Block
cl = {a| ...}
cl = {|a| ...}

Now in the JSR we use this syntax

Code Block
def cl = {a -> ...}

This allows us to use one single token for the separator between the closure parameters and the code in in the closure which works with arbitrarily complex parameter list expressions and default values. e.g.

Code Block
def cl = {String x = "hey", int y = a|b -> println "Values are $x and $y"}
collection.each {int item -> println item}

Property keyword

  • property keyword has been replaced with an annotation
    Code Block
    class Foo {
        property foo
    }
    
    Code Block
    class Foo {
        @Property foo
    }
    

Introduction of the 'def' keyword

  • local variable declarations and fields currently need to be specified with 'def', a modifier, and/or a type. e.g.
    Code Block
    def foo() {
      int x = 123
      y = 456 // classic
    }
    
    def foo() {
      int x = 123
      def y = 456 // JSR
    }
    
    class Foo {
        telson  // classic
        int sharna
    }
    class Foo {
        def telson  // JSR
        int sharna
    }
    
    (Syntactically, the new keyword 'def' acts for methods as a modifier like 'public'.)

For Scripts (as opposed to explicitely declared classes) the syntax is not changed, i.e. variable declarations without 'def' are still allowed, because those variables are automatically created in the script binding if they don't already exist.

Introduction of the 'as' keyword

  • We can change types of objects with using the 'as' keyword,
    e.g.
    Code Block
    def d0 = new Date(2005-1900, 5-1, 7)   // in classic Groovy or Java
    println d0
    
    def d1 = [2005-1900, 5-1, 8] as Date    // since jsr-01
    println d1
    
    Date d2 = [2005-1900, 5-1, 9] as Date   // since jsr-01
    println d2
    
    Date d3 = [2005-1900, 5-1, 10]          // since jsr-01
    println d3
    
    // def n0 = new int[] { 1, 3, 5, 6 }   // Not work. This style is not supported since groovy-1.0-jsr-01.
    
    def n1 = [ 1, 3, 5, 7 ] as int[]
    println n1.class
    println n1.size()
    println n1.length
    println n1[0]
    println n1[-1]
    
    // int[] n2 = [ 2, 4, 6, 8,10 ] as int[]    // work
    int[] n2 = [ 2, 4, 6, 8, 10 ]               // work
    println n2.class
    println n2.size()
    println n2.length
    println n2[0]
    println n2[-1]
    
    // String[] n3 = [ "a", "ab", "abc", "abcd", "abcde", "abcdef" ] as String[]    // work
    String[] n3 = [ "a", "ab", "abc", "abcd", "abcde", "abcdef" ]                   // work
    println n3.class
    println n3.size()
    println n3.length
    println n3[0]
    println n3[-1]
    

Default access level of class members

The default access level for members of Groovy classes has changed from "public" to "protected"

Classic Groovy

Code Block
class Foo {
    readMe_a;
    readMe_b
}
xyz = new Foo(readMe_a:"Hello",readMe_b:"World")
println xyz.readMe_a
println xyz.readMe_b

Now in JSR Groovy

Code Block
class Foo {
    public readMe_a;
    def readMe_b //def is now required because of the "def keyword" change mentioned earlier
}
xyz = new Foo(readMe_a:"Hello",readMe_b:"World")
println xyz.readMe_a
println xyz.readMe_b //errors in JSR Groovy

Array creation

  • no special array syntax. To make the language much cleaner, we now have a single syntax to work with lists and arrays in the JSR. Also note that we can now easily coerce from any collection or array to any array type
Code Block
// classic
args = new String[] { "a", "b" }

// JSR
String[] args = [ "a", "b" ]
def x = [1, 2, 3] as int[]
long[] y = x
  • Be careful: we don't support native multi-dimensional array creation right now.

float and double notation

  • float and double literals cannot start with dot. So
Code Block
x = .123 // classic
def x = 0.123 // JSR

This is to avoid ambiguity with things like ranges (1..2) and so forth

Explicit method pointer syntax

In classic Groovy you could access method pointers automatically if there was no java bean property of the given method name.

e.g.

Code Block
// classic
methodPointer = System.out.println
methodPointer("Hello World")

This often caused confusion; as folks would use a property access to find something and get a method by accident (e.g. typo) and get confused. So now we make getting a method pointer explicit as follows

Code Block
// JSR
def methodPointer = System.out.&println
methodPointer("Hello World")

def foo = ...
def p = foo.&bar

// lets call the bar method on the foo object
p(1, 2, 3)

No 'do ... while()' syntax as yet.

Due to ambiguity, we've not yet added support for do .. while to Groovy

'No Dumb Expression' rule

  • no dumb expression rule, so we will catch dumb expressions (where a carriage return has broken the script). e.g.
    Code Block
    def foo() {
      def x = 1
      +5  // dumb expression!
      return 8
    }
    

Markup and builders

  • markup / builders will change a little, but the classic syntax still applies. Not sure of the new syntax, but we'll have some kinda start/stop syntax to denote a markup block. Maybe a keyword, like
Code Block
markup (builder) { 
  // same stuff as before goes here
}

// or something like this
builder.{
  // same stuff as before goes here
}

Strings and GStrings

  • single and double quote strings can only span one line; for multiple lines use triple quotes
  • heredocs removal - they are kinda ugly anyway (smile). If you want to use them, just use treble quote instead
Code Block
def foo = """
this 
is
a very
long 
string on many
lines
"""
  • escaping of $ inside GStrings must use \$
Code Block
println 'amount is $100'
// same as
println "amount is \$100"
  • A new string definition is also supported which is escaping friendly, and thus particularly friendly for regex notation:
Code Block
if ('abc' =~ /.../) {}
if ('abc' ==~ /.../) {}
'abc'.eachMatch(/.../) {}
['a','b','c'].grep(/a/)

switch('abc'){
       case ~/.../ : whatever
}

assert 'EUOUAE'.matches(/^[aeiou]*$/)
assert 'EUOUAE' ==~ /^[aeiou]*$/
assert 'football'.replaceAll(/foo/, "Bar") == 'Bartball'

Assertions

  • assert uses comma instead of colon to delimit the two parameter form of assertion statement
Code Block
assert 0 <= value : "Must be non-negative"  // classic
Code Block
assert 0 <= value , "Must be non-negative"  // JSR

return/break/continue semantics in closures

NOT YET IMPLEMENTED

  • return/break/continue to behave inside closures like these statements work in other blocks (such as the block on a for() or while() loop. More details here

Integer division

Previously, in Groovy Classic, we used the backward slash as the integer division operator. This operator being confusing with escaping sequences was removed. So instead of \ please use the intdiv() method.

Code Block
int result = 5 \ 3 // classic

Becomes

Code Block
int result = 5.intdiv(3) // JSR

Exclusive range

The operator for creating ranges with the upper bound excluded from the range has changed.

Instead of:

Code Block
range = 0...10

The syntax is now:

Code Block
def range = 0..<10