From: Evan Phoenix Date: 2007-11-09T17:20:23+09:00 Subject: Re: Frightening retry behavior should be deprecated and removed On Nov 8, 2007, at 10:22 PM, David Flanagan wrote: > Yukihiro Matsumoto wrote: >> Hi, >> In message "Re: Frightening retry behavior should be deprecated and >> removed" >> on Wed, 7 Nov 2007 16:05:42 +0900, Charles Oliver Nutter > > writes: >> |I do not believe a target method should be able to cause the >> caller |method to behave this way. I believe this behavior should >> be |deprecated/removed. >> Since this feature is removed from 1.9, you can officially ignore >> this. >> matz. > > It appears that retry can still do its magic re-evaluate the > expression that invoked the iterator thing. But you can't hide the > retry in a method or lambda definition, it can only appear in a > block attached to the iterator, which makes it less frightening, > since the person writing the method invocation expression that may > be retried is the same person writing the retry statement. > Given the fact that retry in a method is gone, I believe we should eliminate it in a block too. Consider the following code: def thing(a); yield; end i = 1 (puts "suck #{i}"; 1).thing(i += 1) { retry } # Prints suck 1, suck 2, suck 3, etc. to infinite. Again, we have the same dangerous semantics Charlie outlined with the retry in a method. The programmer locality is better since hopefully they wrote the retry. But then consider: b = proc { retry } def thing(a); yield; end i = 1 (puts "suck #{i}"; 1).thing(i += 1, &b) # Again, prints suck 1, suck 2, suck 3, etc. to infinite. This has exactly the same problems the method retry does. Very dangerous, terrible locality. Given the fact that retry in a block is used only one place ever I've seen (in drb to try a remote call again), it is again a scary corner that programmers don't go into. Please lets eliminate retry anywhere but in an exception handler. - Evan > Matz: would it be correct to say that retry is now only allowed in > rescue clauses and in blocks? And that it only works for local > invocations of blocks, not in invocations of Procs? > > This code still works in 1.9: > > $tries = 0 > (1..3).each { |x| > print x; > if x==3 > if $tries < 3 > $tries += 1 > retry > end > end > } > > But it doesn't work if we change the block to a Proc: > $tries = 0 > (1..3).each &lambda{ |x| > print x; > if x==3 > if $tries < 3 > $tries += 1 > retry > end > end > } > > And the fake-out-a-looping method thing does not work. > > # Does not work in 1.9 > def repeat_while(x) > if x # If the condition was not nil or false > yield # Run the body of the loop > retry # Retry and re-evaluate loop condition > end > end > > x = 5 > repeat_while(x > 0) { > puts x > x -= 1 > } > > > >