2

I've noticed that if I use the keyword return inside of a block, the entire method returns. I find it confusing that in ruby, you can optionally use the return keyword - it's like: "So what is this thing returning, if anything? Did the developer intend this method to return something?" So I like using return even inside blocks, for example:

def my_method
  items = [ 1, 2, 3 ]

  items_times_ten = items.collect { |o|
    #multiple
    #lines
    #of
    #code ...

    return o * 10  # Ruby exits the method at this point.
  }

  return items_times_ten  #This is never reached.
end

I understand why I don't need to return from the block, but if my block was more intricate, it would seem to help with clarity. My question is, why in the world would Ruby assume that I want to return control out two levels?

If my assumption is incorrect, please correct me. I just want to understand the reasons that control is handled in this way.

3
  • I think this answer could be of help stackoverflow.com/a/2325712/1856239 Commented Feb 11, 2014 at 20:43
  • I redact this entire question. I'm not sure why this surprised me originally - I come from a C# background and if I called return from within a for loop (a weird thing to do), the method would return! Same idea here. I think I just got annoyed trying to solve a problem and got caught up. Commented Feb 11, 2014 at 21:57
  • 1
    Due to some parallels that may be drawn between JavaScript and Ruby closures, this question isn't entirely off base. And calling return inside a C# anonymous delegate would also keep control within the method... don't knock yourself just yet! Commented Feb 12, 2014 at 3:23

3 Answers 3

3

Herein lies one of the primary differences between a block/Proc and a lambda/Method (the other primary difference would be arity). If you don't want a call to return to exit the method, that would infer that you expect that block should be self-contained in its flow control, and be treated as an encapsulated method.

This description is essentially what a lambda is - an anonymous method. However, a standard ruby block is essentially an anonymous Proc, and takes nothing away from the flow control of the method.

As mentioned in the comments, you may be able to use next to escape the block without returning control away from the method. 'May' because next may just continue to the next item that the method iterator is passing to the block.

Related to this, see http://yehudakatz.com/2012/01/10/javascript-needs-blocks/ and Differences between Proc and Lambda

Sign up to request clarification or add additional context in comments.

Comments

2

If you think of a block as some kind of nested function or anonymous method, then you'd expect return to cause the block to the iterator that yielded to it. But blocks are not methods. return always causes the enclosing method to return, no matter how deeply nested within blocks it is.

1 Comment

Yep, I was wrapped up in frustration at this point. It all makes sense. Thanks.
1

The behaviour you're seeing is explained by how Procs and Lambdas behave in ruby in the context of the return keyword.

For instance, the following give you the expected result:

def my_method
  items = [ 1, 2, 3 ]
  a = ->(o){return o * 10}  # lambda
  items_times_ten = items.collect(&a)
  return items_times_ten  #This is never reached.
end

p my_method # [10, 20, 30] 

Essentially, a return within a Proc will stop a method and return the value provided, in the other hand Lambdas will return their value to the method.

Another way around it, if you still want to use a Proc is to use implicit return. For instance:

def my_method
  items = [ 1, 2, 3 ]

  items_times_ten = items.collect { |o|
    o * 10  # Removed the explicit return
  }

  return items_times_ten  #This is never reached.
end

p my_method # [10, 20, 30] 

1 Comment

Right, implicit return is the solution that makes sense.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.