Details

    • Type: New Feature New Feature
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.6-rc-2
    • Component/s: GEP
    • Labels:
      None
    • Number of attachments :
      0

      Description

      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"

        Issue Links

          Activity

          Hide
          james strachan added a comment -

          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]

          Show
          james strachan added a comment - 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]
          Hide
          John Stump added a comment -

          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.

          Show
          John Stump added a comment - 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.
          Hide
          chocolateboy added a comment -

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

          Show
          chocolateboy added a comment - The comma operator would also conflict with tuples, which are also planned.
          Hide
          Paul King added a comment - - edited
          Show
          Paul King added a comment - - edited See also the GEP as it currently stands: http://docs.codehaus.org/display/GROOVY/Multiple+Assignment+Proposal
          Hide
          blackdrag blackdrag added a comment -

          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

          Show
          blackdrag blackdrag added a comment - 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
          Hide
          Paul King added a comment -

          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
          
          Show
          Paul King added a comment - 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
          Hide
          Cazacu Mihai added a comment -

          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>

          Show
          Cazacu Mihai added a comment - 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>
          Hide
          Chanwit Kaewkasi added a comment -

          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]

          Show
          Chanwit Kaewkasi added a comment - 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]
          Hide
          Paul King added a comment -

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

          (one, two) = "The quick brown fox".tokenize()
          assert one == 'The'
          assert two == 'quick'
          
          Show
          Paul King added a comment - Current behavior doesn't have special head/tail treatment. (one, two) = "The quick brown fox" .tokenize() assert one == 'The' assert two == 'quick'
          Hide
          blackdrag blackdrag added a comment -

          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.

          Show
          blackdrag blackdrag added a comment - 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.
          Hide
          codecraig added a comment -

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

          Show
          codecraig added a comment - So what's the final result, what's been provided for "multiple assignment"?
          Hide
          Paul King added a comment -

          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

          Show
          Paul King added a comment - 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
          Show
          Paul King added a comment - Or this test: http://svn.groovy.codehaus.org/browse/~raw,r=13691/groovy/trunk/groovy/groovy-core/src/test/gls/statements/MultipleAssignmentTest.groovy
          Hide
          codecraig added a comment -

          Perfect, thanks.

          Show
          codecraig added a comment - Perfect, thanks.

            People

            • Assignee:
              blackdrag blackdrag
              Reporter:
              james strachan
            • Votes:
              2 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: