113

Is there any possibility to return multiple values from method? Something like this:

def someMethod()
  return ["a", 10, SomeObject.new]
end

[a, b, c] = someMethod
armitus
  • 712
  • 5
  • 20
ceth
  • 44,198
  • 62
  • 180
  • 289

5 Answers5

167
def sumdiff(x, y)
  return x+y, x-y
end
#=> nil

sumdiff(3, 4)
#=> [7, -1]

a = sumdiff(3,4)
#=> [7, -1]
a
#=> [7, -1]

a,b=sumdiff(3,4)
#=> [7, -1]
a
#=> 7
b
#=> -1

a,b,c=sumdiff(3,4)
#=> [7, -1]
a
#=> 7
b
#=> -1
c
#=> nil
amenthes
  • 3,117
  • 1
  • 32
  • 38
Aditya Mukherji
  • 9,099
  • 5
  • 43
  • 49
  • You should use code formatting, not text formatting. Indent lines four spaces and the weirdness caused by irb's `>>` prompt will go away. – Chris Lutz Dec 25 '09 at 15:31
  • 4
    Since an explicit return is considered non-idiomatic Ruby, you can also use an implicit return by explicitly putting the return values in a list: `def foo_and_bar; ['foo', 'bar']; end` – Dennis Dec 09 '14 at 13:06
45

Ruby has a limited form of destructuring bind:

ary = [1, 2, 3, 4]
a, b, c = ary
p a # => 1
p b # => 2
p c # => 3

a, b, *c = ary
p c # => [3, 4]

a, b, c, d, e = ary
p d # => 4
p e # => nil

It also has a limited form of structuring bind:

 a = 1, 2, 3
 p a # => [1, 2, 3]

You can combine those two forms like so:

a, b = b, a # Nice way to swap two variables

a, b = 1, 2, 3
p b # => 2

def foo; return 1, 2 end
a, b = foo
p a # => 1
p b # => 2

There's several other things you can do with destructuring / structuring bind. I didn't show using the splat operator (*) on the right hand side. I didn't show nesting (using parantheses). I didn't show that you can use destructuring bind in the parameter list of a block or method.

Here's just an appetizer:

def foo(((a, b, c, d), e, *f), g, *h)
  local_variables.sort.each do |lvar| puts "#{lvar} => #{eval(lvar).inspect}" end
end

foo([[1, 2, 3], 4, 5, 6], 7, 8, 9)
# a => 1
# b => 2
# c => 3
# d => nil
# e => 4
# f => [5, 6]
# g => 7
# h => [8, 9]
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
17

Whilst returning multiple values is often useful, I usually find it's a pointer to a new object requirement.

That is, I usually find that those return values are closely tied together in meaning/context and are passed around as such. So in these cases I would create a new object to tie these together. It's a particular code smell I've learnt to recognise.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 4
    more freedom, more responsibility. Experienced rubyist would take advantage of it and write some beautiful codes. while ruby rookies can make things worse. – fengd Nov 05 '13 at 17:07
  • 1
    Well clearly that's not always the case, or else things like `chunk` wouldn't exist. Excellent principle though. Code smell indeed. Rock on. – Darth Egregious Nov 26 '15 at 16:18
7

You can achieve this returning an array too, like

def sumdiff(x, y)
    [x+y, x-y]
end

which seems functionally equivalent to

def sumdiff(x, y)
    return x+y, x-y
end
Zack Xu
  • 11,505
  • 9
  • 70
  • 78
1

You can also ignore the second return value by using this:

a,=sumdiff(3,4)