85

What is the difference between return and just putting a variable such as the following:

no return

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  mood
end

return

def write_code(number_of_errors)
  if number_of_errors > 1
    mood =  "Ask me later"
  else
    mood = puts "No Problem"
  end  
  return mood
end
AnneTheAgile
  • 9,932
  • 6
  • 52
  • 48
thenengah
  • 42,557
  • 33
  • 113
  • 157

7 Answers7

126

return allows you to break out early:

def write_code(number_of_errors)
  return "No problem" if number_of_errors == 0
  badness = compute_badness(number_of_errors)
  "WHAT?!  Badness = #{badness}."
end

If number_of_errors == 0, then "No problem" will be returned immediately. At the end of a method, though, it's unnecessary, as you observed.


Edit: To demonstrate that return exits immediately, consider this function:

def last_name(name)
  return nil unless name
  name.split(/\s+/)[-1]
end

If you call this function as last_name("Antal S-Z"), it will return "S-Z". If you call it as last_name(nil), it returns nil. If return didn't abort immediately, it would try to execute nil.split(/\s+/)[-1], which would throw an error.

AnneTheAgile
  • 9,932
  • 6
  • 52
  • 48
Antal Spector-Zabusky
  • 36,191
  • 7
  • 77
  • 140
  • ok, good example. so return stores the return value but lets the rest of the method execute. Can't wait to use it. – thenengah Jan 05 '11 at 06:55
  • 5
    No, the other way around: `return` *immediately* exits the method. If you think about that example, it wouldn't be useful to compute the badness if you know everything's ok. I'll edit my answer to make that clearer. – Antal Spector-Zabusky Jan 05 '11 at 06:56
  • 9
    You may use `return`, `break` etc. without parameter - they'll return `nil` by default. – Nakilon Jan 05 '11 at 08:11
42

Using "return" is unnecessary if it is the last line to be executed in the method, since Ruby automatically returns the last evaluated expression.

You don't even need that final "mood", nor do you need those assignments in the IF statement.

def write_code(number_of_errors)
    if number_of_errors > 1
       "ERROR"
    else
       "No Problem"
    end  
end

puts write_code(10)

Output:

ERROR

AnneTheAgile
  • 9,932
  • 6
  • 52
  • 48
danneu
  • 9,244
  • 3
  • 35
  • 63
4

Ruby returns always! the best way is

def write_code(number_of_errors)
  (number_of_errors > 1)? "ERROR" : "No Problem"
end

it means that if number_of_errors > 1 it will return ERROR else No Problem

AnneTheAgile
  • 9,932
  • 6
  • 52
  • 48
msroot
  • 817
  • 11
  • 13
4

Its nice ruby gives this good feature of not specifying return statement explicitly but I just feel, as a programming standard, one should always strive to specify "return" statements wherever required. This helps in making code more readable for someone who is coming from different background like C++, Java, PHP etc. and learning ruby. "return" statement will not harm anything, so why skip conventional and more standard way of returning from functions.

Kush
  • 909
  • 1
  • 8
  • 14
  • 4
    "so why skip conventional and more standard way of returning from functions" ← because *in Ruby*, omitting `return` *is* the conventional standard. If you see a `return` in well-styled Ruby code, it should be there for a reason, such as [breaking out early](http://stackoverflow.com/a/4601517/27358). Trying to apply code style conventions from one language to another just makes it more difficult to onboard experienced programmers and keep your own code style consistent. – David Moles Jun 09 '15 at 18:59
  • i still catch myself putting semi-colons on the end of lines – gdbj Oct 15 '16 at 02:44
  • Isn't that #2 in the Zen of Ruby, "implicit is better than explicit"? ;-) – Mark Mar 23 '17 at 13:09
4

I use return when I'm going through a list, and I want to exit the function if any member of the list meets a criteria. I could accomplish this with a single statement like:

list.select{|k| k.meets_criteria}.length == 0

in some situations, but

list.each{|k| return false if k.meets_criteria}

is one line too--with, to my mind, some added flexibility. For example, the first example assumes that this is the only line in the method, and that we want to return from this point no matter what. But if this is a test to see whether it is safe to proceed with the rest of the method, the first example will need to handle that in a different way.

EDIT:

To add some flexibility, consider the following line of code:

list_of_method_names_as_symbols.each{|k| list_of_objects.each{|j| return k if j.send(k)}}

I'm sure this can be accomplished, in one line, without return, but off the top of my head I don't see how.

But this is now a fairly flexible line of code that can be called with any list of boolean methods and a list of objects that implement those methods.

EDIT

It should be noted that I'm assuming this line is inside a method, not a block.


But this is mostly a stylistic choice, I think that in most situations, you can and possibly should avoid using return.

philosodad
  • 1,808
  • 14
  • 24
2

One small caution for those coming from other languages. Say you have a function like the OP's, and you make use of the "last thing computed" rule to set your return value automagically:

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
end

and let's say you add a debugging (or logging) statement:

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
end

Now guess what. You've broken your code, because the puts returns nil, which now becomes the return value from the function.

The solution is to get in the habit of always explicitly putting the return value on the last line, the way the OP did:

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
  mood
end
Tom Hundt
  • 1,694
  • 19
  • 18
-1

Unnecesarity of return at the last line in function is just syntaxic sugar of Ruby. In most procedural languages you need to write return in each (non-void in C++) function.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
  • 4
    I wouldn't call it a syntactic sugar... the core feature here is that nearly everything is an **expression**. `if` statements, statement blocks. That's what allows this expressivity. – Karoly Horvath Jan 05 '17 at 23:09
  • I agree with Karoly — it's not syntactic sugar because everything is an expression. – fatuhoku Mar 29 '17 at 15:35