Issue Details (XML | Word | Printable)

Key: GROOVY-158
Type: New Feature New Feature
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Jochen Theodorou
Reporter: james strachan
Votes: 2
Watchers: 3
Operations

If you were logged in you would be able to see more operations.
groovy

Multiple assignment

Created: 27/Jan/04 06:46 AM   Updated: 24/Feb/09 08:58 PM   Resolved: 22/Apr/08 07:13 AM
Return to search
Component/s: GEP
Affects Version/s: None
Fix Version/s: 1.6-rc-2

Time Tracking:
Not Specified

Issue Links:
Related
 
dependent
 


 Description  « Hide

Support for multiple assignment to simulate multiple return types:

a, b, c = someFunctionReturningAListOfThreeElements()

If more elements are returned than the number of variables to assign values to, we could get the head of list in the first variable and the rest of the list in the second variable:

head, tail = [1,2,3,4]
assert head == 1
assert tail == [2,3,4]

Can also be used for variable swapping
x, y = [y, x]
x, y = y, x

We have to be careful with varibale definitions, because currently:
def a, b, c = someFunctionReturningList()
because currently, a and b would be null, while c would be assigned to the value of the return of the function.

A GEP should be created to present all the possibilities, syntax, edge cases.

Further ideas (subsequent feature enhancements) could be considered like fetching matching groups from regex:
def regex = ~/firstname: (.), name: (.)/
firstname, name = ("firstname: Guillaume, name: Laforge") =~ regex)
assert firstname == "Guillaume"
assert name == "Laforge"



james strachan added a comment - 16/Feb/04 02:11 AM

We should also expand this to include list indexing for the lvalue. e.g.

list[a, b, c] = someListExpr

would expand to

t = someListExpr
list[a] = t[0]
list[b] = t[1]
list[c] = t[2]


John Stump added a comment - 21/Jul/04 11:12 AM

Your initial syntax implies that groovy will never support the comma operator, because if we did there might be a conflict. I personally never use the comma operator in Java except in for() loops, but as I understand it, Groovy will someday support the standard for() loop.


chocolateboy added a comment - 26/Jun/05 08:36 PM

The comma operator would also conflict with tuples, which are also planned.


Paul King added a comment - 30/Nov/07 09:04 PM - edited

Jochen Theodorou added a comment - 22/Apr/08 07:13 AM

since there was low feedback on this the only form that is supported atm is

a,b = [1,2]

meaning no declaration and the number of arguments must match


Paul King added a comment - 22/Apr/08 06:32 PM

Just as a comment for future Jira searchers. This does allow Groovy to do the often discussed swap two variables without a temp variable! E.g.:

def a = 1
def b = 2
[a, b] = [b, a]
println a // => 2
println b // => 1

Cazacu Mihai added a comment - 21/Feb/09 05:14 AM

This code doesn't work:
<code>
def a = 1
def b = 2
[a, b] = [b, a]
println a // => 2
println b // => 1
</code>

Environment:

  • Groovy Version: 1.6.0 JVM: 1.6.0_12

Error:
<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 at line: 4 column: 8. File: /home/ms/work/groovy/test04.groovy @ line 4, column 8.
[a, b] = [b, a]
^

1 error

</error>


Chanwit Kaewkasi added a comment - 21/Feb/09 05:56 AM

per http://jira.codehaus.org/browse/GROOVY-1543?focusedCommentId=150396&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_150396

it's now:

def a = 1
def b = 2
(a,b) = [b, a]

to be working.

However, I think

def (head, tail) = [1,2,3,4]
would work as in the issue descrption:

head should be 1
and tail should be [2,3,4]


Paul King added a comment - 21/Feb/09 06:32 AM

Current behavior doesn't have special head/tail treatment.

(one, two) = "The quick brown fox".tokenize()
assert one == 'The'
assert two == 'quick'

Jochen Theodorou added a comment - 21/Feb/09 07:21 AM

in discussion was to mark an element to take the surplus parts as list.. for example like:

(head, *tail) = [1,2,3,4]
assert head == 1
assert tail = [2,3,4]

(*head, tail) = [1,2,3,4]
assert head == [1,2,3]
assert tail = 4

(head, *middle, end) = [1,2,3,4]
assert head == 1
assert middle = [2,3]
assert end == 4

I thought about doing maybe even something like this:

(*a,3,*b) = [1,2,3,4]
assert a == [1,2]
assert b == [4]

But that is just an idea, not really discussed and I need use cases for these first. And normally you don't look for use cases because you want to have a feature, instead you have a problem and think of a feature to solve that use case.

Basically you can have these cases

(a,b) = [1,2]     // b== 2, or b== [2] ?
(a,b) = [1]        // exception, or b==[], or b==null?
(a,b) = [1,2,3]  // b==2, or b==[2,3], or exception?

I decided for b==2, exception, b==2. But any other version seems to be equally reasonable. With a fix head/tail logic for example I would expect b==[2], b==[], b==[2,3]. But is this really multiple assignment? It looks more like a combined car/cdr operation, which does not exactly fit into Groovy atm.

If you are interested in getting head tail logic into groovy, then I suggest you start a thread on the user list for it.


codecraig added a comment - 24/Feb/09 06:41 PM

So what's the final result, what's been provided for "multiple assignment"?


Paul King added a comment - 24/Feb/09 08:31 PM

My last comment and Jochen's last example briefly show what is currently possible or check out the following test:
http://svn.groovy.codehaus.org/browse/~raw,r=13691/groovy/trunk/groovy/groovy-core/src/test/gls/statements/MultipleAssignmentDeclarationTest.groovy



codecraig added a comment - 24/Feb/09 08:58 PM

Perfect, thanks.