65

I want to return multiple values from a function written in groovy and receive them , but i am getting an error

class org.codehaus.groovy.ast.expr.ListExpression, with its value '[a, b]', is a bad expression as the left hand side of an assignment operator

My code is

int a=10
int b=0
println "a is ${a} , b is ${b}"
[a,b]=f1(a)
println "a is NOW ${a} , b is NOW ${b}"

def f1(int x) {   
  return [a*10,a*20]
}
tim_yates
  • 167,322
  • 27
  • 342
  • 338
Nikhil Sharma
  • 2,221
  • 6
  • 25
  • 31
  • Helpful link on how to return multiple values for different programming languages https://rosettacode.org/wiki/Return_multiple_values#Groovy – biniam Nov 03 '16 at 16:05

3 Answers3

116

You almost have it. Conceptually [ a, b ] creates a list, and ( a, b ) unwraps one, so you want (a,b)=f1(a) instead of [a,b]=f1(a).

int a=10
int b=0
println "a is ${a} , b is ${b}"
(a,b)=f1(a)
println "a is NOW ${a} , b is NOW ${b}"

def f1(int x) {
    return [x*10,x*20]
}

Another example returning objects, which don't need to be the same type:

final Date foo
final String bar
(foo, bar) = baz()
println foo
println bar

def baz() {
    return [ new Date(0), 'Test' ]
}

Additionally you can combine the declaration and assignment:

final def (Date foo, String bar) = baz()
println foo
println bar

def baz() {
    return [ new Date(0), 'Test' ]
}
Justin Piper
  • 3,154
  • 1
  • 20
  • 14
  • Added a line to the answer to highlight the change the OP needed to make since different brackets in 8 lines of code can be easily missed. – Sled Jan 14 '14 at 14:54
  • If the return types are object, then what will happen? Can anyone explain please. I want to return multiple object from a method. – Emdadul Sawon May 22 '17 at 08:59
  • It's pretty much the same. I'll add an example with dates. – Justin Piper May 22 '17 at 17:35
  • The more technically correct and common term for what Justin wrote above as "unwraps" is "destructuring"; in this case, the calling statements are destructuring assignment statements. See [1.2.1. Multiple assignment](http://groovy-lang.org/semantics.html#_multiple_assignment) for details. – Steve Byrne Mar 24 '19 at 14:48
45

You can declare and assign the variables in which the return values are stored in one line like this, which is a slightly more compact syntax than that used in Justin's answer:

def (int a, int b) = f1(22)

In your particular case you may not be able to use this because one of the variables passed to f1 is also used to store a return value

Dónal
  • 185,044
  • 174
  • 569
  • 824
  • According to [Groovy Goodness](http://mrhaki.blogspot.de/2009/09/groovy-goodness-multiple-assignments.html) you don't even need the `int` declarations inside the parentheses. – sschuberth Nov 30 '16 at 15:29
  • @sschuberth True, but you might want it if you want the static type checking/coercion that comes with declaring types – M. Justin Feb 22 '23 at 20:17
6

When running Groovy in the context of Jenkins pipeline job the above answers do not work (at least on version 2.60.2), but the following does:

node {
    obj = ret2()
    fw = obj[0]
    lw = obj[1]
    echo "fw=${fw}"
    echo "lw=${lw}"
}

def ret2()
{
    return [5, 7]
}

Or alternatively:

node {
    obj = ret2()
    fw = obj.a
    lw = obj.b
    echo "fw=${fw}"
    echo "lw=${lw}"
}

def ret2()
{
    return [a:5, b:7]
}