# Everyone's favorite flow control: retry

**URL:** <https://www.ruby-forum.com/t/everyones-favorite-flow-control-retry/196531>\
**Category:** Ruby\
**Created:** [December 3, 2007, 7:04am UTC](https://www.ruby-forum.com/t/everyones-favorite-flow-control-retry/196531 "2007-12-03T07:04:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![headius](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/7c8e57/32.png) [@headius](https://www.ruby-forum.com/u/headius)\
**Post date:** [December 3, 2007, 7:04am UTC](https://www.ruby-forum.com/t/everyones-favorite-flow-control-retry/196531/1 "2007-12-03T07:04:59Z")

</div>

Today I was thinking about retry support in JRuby, and figured we’ve  
reached a decision point.

retry is a tricky little bugger. It works the way it does in MRI largely  
because of the way the interpreter works; so in that sense it’s very  
implementation specific. So here’s some example code, see if you can  
figure out what it prints.

$count = 0  
class Foo  
def initialize  
$count += 1  
@value = $count  
end

def do\_retry(i)  
puts “value is #{@value} and i is #{i}”  
retry  
end  
end

a = 0  
Foo.new.do\_retry(a += 1) {}

Give up? Here’s the answer:

value is 1 and i is 1  
value is 2 and i is 2  
value is 3 and i is 3

The trick here is the retry. A retry can only be used in a rescue block  
(which is ok), inside a block, or inside a method that’s been passed a  
block. Excluding rescue, retry causes the original call to the method  
with the block to reevaluate. And I don’t just mean re-execute with the  
same values, I mean re-evaluate both the receiver and the arguments and  
make the call again.

So for example, this method invocation

def foo(a); puts 3; retry; end

(print 1; self).foo((print 2; nil)) {}

Prints out “123” forever, because the receiver (the (print 1; self) bit)  
and the arguments (the (print 2; nil) bit) get executed again. Goofy,  
right?

This also affects retry within a block

def foo(a); puts 3; yield; end

(print 1; self).foo((print 2; nil)) { retry }

This also prints “123” repeatedly.

The problem I’ve run into is that it’s really cumbersome to implement  
this correctly in the compiler, cumbersome enough I’m debating whether  
we’ll support it. There’s a few reasons for this:

- retry is handled using exception; so every method call that takes a  
block would have to be wrapped with exception-handling for retry to  
work. Exception-handling is expensive, even if no exceptions are  
actually raised. It would also add a significant amount of code.
- there’s no way to know that a method will be reevaluated by looking at  
it, which makes it both dangerous and impossible to predict.
- nobody understands retry, and nobody uses it.

As I understand it, retry in a method body is going away in 1.9, so it  
should be considered deprecated behavior. So far, retry in a block is  
not yet going away, though I’d prefer it did. Actually, I wish this  
behavior never existed, because it makes a lot of assumptions about the  
way Ruby is implemented. Ask if you want to know more about that.

I’m looking for input on this. If there’s a way to implement it I have  
missed, please tell me. If you have a concern with this feature being  
disabled, please tell me (it won’t affect retry within rescue blocks).  
If you want to talk about it more, please tell me.

- Charlie
