Forum: Ruby ruby1.9 and the retry keyword

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
A5ae84b6af0a67cdea1db87706a11a6f?d=identicon&s=25 Yoann Guillot (Guest)
on 2009-04-19 16:20
(Received via mailing list)
Hi

It seems that the 'retry' keyword is not supported anymore in ruby1.9 to
restart a running iteration from the beginning.

Is there a way to achieve the old behavior, preferably in a 1.8
compatible
way ?

$ ruby1.8 -ve '[1, 2].each { puts "bla" ; retry }'
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
bla
bla
bla
^C

$ ruby1.9 -ve '[1, 2].each { puts "bla" ; retry }'
ruby 1.9.2dev (2009-04-19) [i686-linux]
-e:1: Invalid retry
-e: compile error (SyntaxError)
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-04-19 18:11
(Received via mailing list)
On 19.04.2009 16:20, Yoann Guillot wrote:

> It seems that the 'retry' keyword is not supported anymore in ruby1.9 to
> restart a running iteration from the beginning.

This cannot be, "retry" works in 1.9.1:

[robert@ora01 ~]$ irb19
irb(main):001:0> i = 5
=> 5
irb(main):002:0> begin
irb(main):003:1* puts i
irb(main):004:1> raise "foo"
irb(main):005:1> rescue Exception
irb(main):006:1> i -= 1
irb(main):007:1> retry if i > 0
irb(main):008:1> end
5
4
3
2
1
=> nil
irb(main):009:0> RUBY_VERSION
=> "1.9.1"
irb(main):010:0>

> Is there a way to achieve the old behavior, preferably in a 1.8 compatible
> way ?
>
> $ ruby1.8 -ve '[1, 2].each { puts "bla" ; retry }'
> ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
> bla
> bla
> bla
> ^C

"retry" without "rescue" seems pointless to me.  As far as I can see
"retry"'s main purpose is repetition in case of exceptions.  The use
that you demonstrate looks like a untypical and probably unwanted idiom
which accidentally happened to work in 1.8.* to me.

> $ ruby1.9 -ve '[1, 2].each { puts "bla" ; retry }'
> ruby 1.9.2dev (2009-04-19) [i686-linux]
> -e:1: Invalid retry
> -e: compile error (SyntaxError)

Apparently the _syntax_ was changed to allow "retry" only in "rescue"
clauses - which makes perfectly sense for me.  I am not the definitive
source but to me it looks like 1.9 fixes a misbehavior of 1.8 - if
that's the case I would not want to reintroduce this just to make 1.9
more compatible to 1.8.  In fact, 1.9 purposefully *does* have some
incompatibilities.

Kind regards

  robert
87ef5d1e14b148eb596433bc17ffe690?d=identicon&s=25 Leo (Guest)
on 2009-04-19 18:41
(Received via mailing list)
> It seems that the 'retry' keyword is not supported anymore in ruby1.9 to
> restart a running iteration from the beginning.

Are you sure you don't want to use 'redo'?

$ ruby -ve '[1, 2].each { puts "bla" ; redo }'
ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-cygwin]
bla
bla
...
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-04-19 18:53
(Received via mailing list)
On Apr 19, 2009, at 9:20 AM, Yoann Guillot wrote:

> It seems that the 'retry' keyword is not supported anymore in
> ruby1.9 to
> restart a running iteration from the beginning.

As Robert said, it's no longer supported in iteration.  It still works
in a rescue clause.

> Is there a way to achieve the old behavior, preferably in a 1.8
> compatible way ?

You bet.

> $ ruby1.8 -ve '[1, 2].each { puts "bla" ; retry }'

loop do
   puts "bla"
end

James Edward Gray II
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-04-19 19:02
(Received via mailing list)
On Sun, Apr 19, 2009 at 9:50 AM, James Gray <james@grayproductions.net>
wrote:
>
> You bet.
>
>> $ ruby1.8 -ve '[1, 2].each { puts "bla" ; retry }'
>
> loop do
>  puts "bla"
> end

That mimics the example (where the retry is unconditional), but
clearly isn't a general solution; If "redo" works on 1.9 (which is
similar to retry, but different in conditions not relevant to the
question), that may be the answer.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-04-19 19:11
(Received via mailing list)
On Apr 19, 2009, at 12:01 PM, Christopher Dicely wrote:

>>> $ ruby1.8 -ve '[1, 2].each { puts "bla" ; retry }'
>>
>> loop do
>>  puts "bla"
>> end
>
> That mimics the example (where the retry is unconditional), but
> clearly isn't a general solution;

I'll be surprised if more complex examples can't be similarly
converted fairly easily.  That was kind of my point.  I meant the code
to say, take a step back and think what is this trying to do…

James Edward Gray II
A5ae84b6af0a67cdea1db87706a11a6f?d=identicon&s=25 Yoann Guillot (Guest)
on 2009-04-19 20:07
(Received via mailing list)
On Mon, Apr 20, 2009 at 01:41:05AM +0900, Leo wrote:
>
redo reruns the current iteration, retry restarted the whole iteration

[1, 2].each { |i| puts i ; redo if i == 2 }
> 1 2 2 2 2 2 2
[1, 2].each { |i| puts i ; retry if i == 2 }
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-04-19 20:16
(Received via mailing list)
On Apr 19, 2009, at 1:07 PM, Yoann Guillot wrote:

>> bla
>> ...
>>
>
> redo reruns the current iteration, retry restarted the whole iteration
>
> [1, 2].each { |i| puts i ; redo if i == 2 }
>> 1 2 2 2 2 2 2
> [1, 2].each { |i| puts i ; retry if i == 2 }
>> 1 2 1 2 1 2 1

$ ruby_dev -ve '[1, 2].cycle { |i| puts i }'
ruby 1.9.2dev (2009-04-13) [i386-darwin9.6.0]
1
2
1
2
1
2
1
2
-e:1:in `write': Interrupt
  from -e:1:in `puts'
  from -e:1:in `puts'
  from -e:1:in `block in <main>'
  from -e:1:in `cycle'
  from -e:1:in `<main>'

James Edward Gray II
A5ae84b6af0a67cdea1db87706a11a6f?d=identicon&s=25 Yoann Guillot (Guest)
on 2009-04-19 20:18
(Received via mailing list)
On Mon, Apr 20, 2009 at 02:10:33AM +0900, James Gray wrote:
> On Apr 19, 2009, at 12:01 PM, Christopher Dicely wrote:
>
>> That mimics the example (where the retry is unconditional), but
>> clearly isn't a general solution;
>
> I'll be surprised if more complex examples can't be similarly converted
> fairly easily.  That was kind of my point.  I meant the code to say, take
> a step back and think what is this trying to do?
>

My code walks an array, and may change the current element, which is
allowed
without breaking the iteration.

I have also a special case where i have to change a whole subsection of
the
array, this was the case where i used 'retry'

eg
ary.each { |e|
  case e
  when foo
    ary[ary.index(e)] = foo(e)
  when bar
  when ...
  when baz
    ary[ary.index(e), 12] = [flublu]
    retry
  end
}

Sure, i could use map or many other ways, my code is quite ugly anyway.
I was just surprised by the change of behavior.

I don't see the point in removing capabilities from the language
(restarting
an iteration from within), but I can sure live with it.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-04-19 20:38
(Received via mailing list)
On Apr 19, 2009, at 1:17 PM, Yoann Guillot wrote:

>     ary[ary.index(e)] = foo(e)
>   when bar
>   when ...
>   when baz
>     ary[ary.index(e), 12] = [flublu]
>     retry
>   end
> }
>
> Sure, i could use map or many other ways, my code is quite ugly
> anyway.

Yeah, for a case like this, I would probably just resort to tracking
an index in a variable and using a boring while loop.  90% of the time
it's wrong to track your own index in Ruby, but I think you're
squarely in the special 10% here.

Really, you should already be using each_with_index() above because
your repeated calls to index() are inefficient for big data sets
(rewalking possibly large portions of the Array) and they break if the
data set contains duplicate entries.

Plus, I'm just not comfortable relying on the iterators to do the
right thing while I edit the collection out from underneath them.
Obviously it was working for you, but I'm not confident enough to
trust it under all cases.

> I don't see the point in removing capabilities from the language
> (restarting an iteration from within), but I can sure live with it.

It was done because retry had some nasty side effects and was causing
performance issues:

http://markmail.org/message/laisvqelyjmgh56p#query...
%20remove+page:1+mid:fxoxlphjdndatp4m+state:results

James Edward Gray II
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2009-04-19 23:54
(Received via mailing list)
On Sun, Apr 19, 2009 at 7:17 PM, Yoann Guillot <john-rubytalk@ofjj.net>
wrote:
>
>                ary[ary.index(e)] = foo(e)
>
> I don't see the point in removing capabilities from the language (restarting
> an iteration from within), but I can sure live with it.
>
> --
> Yoann
>
>

You could do this I guess:

ary = [:foo, :bar, :baz, :foo]

def foo(e)
  :bom
end

class Retry < StandardError
end

begin
  ary.each { |e|
    case e
    when :foo
      ary[ary.index(e)] = foo(e)
    when :bom
      ary[ary.index(e)] = :foobom # to show retry
    when :baz
      ary[ary.index(e), 12] = [:flublu]
      raise Retry
    end
  }
rescue Retry
  retry
end
p ary
__END__
[:foobom, :bar, :flublu]

but as you point out, this is not restarting the iteration from within.

Regards,
Sean
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-04-20 10:43
Or using throw/catch. You can also factor out the pattern, for example:

def retryable
  loop do
    catch(:retry) do
      yield
      return
    end
  end
end

ary = [:foo, :bar, :baz, :foo]

def foo(e)
  :bom
end

retryable do
  ary.each { |e|
    case e
    when :foo
      ary[ary.index(e)] = foo(e)
    when :bom
      ary[ary.index(e)] = :foobom # to show retry
    when :baz
      ary[ary.index(e), 12] = [:flublu]
      throw :retry
    end
  }
end
p ary
__END__
[:foobom, :bar, :flublu]
This topic is locked and can not be replied to.