2

In venturing into Ruby, I started toying with things like the way Ruby returns the last thing you've mentioned even if it was not after a return construct. However, why don't these two snippets work the same way? Shouldn't they?

module Enumerable
  def palindrome?
    reversed_self = self.reverse
    self.each_with_index {|el,index|
      unless self[index]==reversed_self[index]
        return false ## <-----
      end
    }
    true
  end
end

all good so far: puts ['foo','bar','baz'].palindrome? prints 'false'

and

module Enumerable
  def palindrome?
    reversed_self = self.reverse
    self.each_with_index {|el,index|
      unless self[index]==reversed_self[index]
        false ## <------
      end
    }
    true
  end
end

puts ['foo','bar','baz'].palindrome? prints 'true' for some reason

What's the science behind this?

Felipe
  • 11,557
  • 7
  • 56
  • 103

3 Answers3

3

Ruby will return the value of the last executed expression in a method. The false in the second version is not the last expression, there's nothing telling Ruby to stop executing at that point so it will chug along until the method ends.

return is a way to explicitly say to Ruby to stop executing and return a value.

Theo
  • 131,503
  • 21
  • 160
  • 205
2

Not quite! A return from inside a block is different from a return inside a lambda, as mentioned in my answer here. When you return from inside a block, you're returning from the entire method rather than just the block.

We can illustrate this as follows:

return :foo # => LocalJumpError: unexpected return
[1, 2, 3].map { return :foo } # => LocalJumpError: unexpected return
[1, 2, 3].map { :foo } # => [:foo, :foo, :foo]

Normally, this doesn't happen with lambdas:

l = lambda { return :foo }
l.call # => :foo
[1, 2, 3].map { l.call } # => [:foo, :foo, :foo]

But when we try to pass the lambda as a block to the method, the behavior changes back:

[1, 2, 3].map &l # => LocalJumpError: unexpected return
Community
  • 1
  • 1
jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • So you mean that when there's a `return` clause inside a block we return from the block only? I think you got confused in your answer? – Felipe Mar 11 '12 at 13:40
  • No, it's exactly the opposite. A return from inside the block tries to return from the enclosing method. I edited my second sentence to clarify. – jtbandes Mar 11 '12 at 13:40
1

If no return statement is present, then return value of a function is the last value evaluated. In the second snipped the last value is always true.

First snippet returns early with false. Second does nothing with that false, it's discarded.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367