Robert Klemme
2/7/2006 11:21:00 AM
Martin DeMello wrote:
> Could someone explain why this code works:
>
> def repeat(condition)
> puts "condition: #{condition}"
> yield
> retry if not condition
> end
>
> j=0
> repeat (j >= 10) do
> puts j
> j+=1
> end
>
> puts "after loop, j = #{j}"
>
> I'd have expected repeat (j >= 10) to pass "false" into the method,
> which would then yield repeatedly to the do/end block, never seeing
> the (condition) part again.
retry actually reevaluates the method invocation. If you use
set_trace_func you'll see something like this with the attached script:
["line", "/c/temp/ruby/retry.rb", 8, nil, #<Binding:0x100f63e8>, false]
["line", "/c/temp/ruby/retry.rb", 9, nil, #<Binding:0x100f63a0>, false]
["c-call", "/c/temp/ruby/retry.rb", 9, :>=, #<Binding:0x100f6250>, Fixnum]
["c-return", "/c/temp/ruby/retry.rb", 9, :>=, #<Binding:0x100f6130>,
Fixnum]
["call", "/c/temp/ruby/retry.rb", 2, :repeat, #<Binding:0x100f5f08>,
Object]
["line", "/c/temp/ruby/retry.rb", 3, :repeat, #<Binding:0x100f5ec0>,
Object]
["c-call", "/c/temp/ruby/retry.rb", 3, :to_s, nil, FalseClass]
["c-return", "/c/temp/ruby/retry.rb", 3, :to_s, nil, FalseClass]
["c-call", "/c/temp/ruby/retry.rb", 3, :puts, #<Binding:0x100f5b30>,
Kernel]
["c-call", "/c/temp/ruby/retry.rb", 3, :write, #<Binding:0x100f5a10>, IO]
condition: false["c-return", "/c/temp/ruby/retry.rb", 3, :write,
#<Binding:0x100f58d8>, IO]
["c-call", "/c/temp/ruby/retry.rb", 3, :write, #<Binding:0x100f57a0>, IO]
["c-return", "/c/temp/ruby/retry.rb", 3, :write, #<Binding:0x100f5680>,
IO]
["c-return", "/c/temp/ruby/retry.rb", 3, :puts, #<Binding:0x100f5560>,
Kernel]
["line", "/c/temp/ruby/retry.rb", 4, :repeat, #<Binding:0x100f5440>,
Object]
["line", "/c/temp/ruby/retry.rb", 10, nil, #<Binding:0x100f5230>, false]
["c-call", "/c/temp/ruby/retry.rb", 10, :puts, #<Binding:0x100f51e8>,
Kernel]
["c-call", "/c/temp/ruby/retry.rb", 10, :to_s, #<Binding:0x100f50c8>,
Fixnum]
["c-return", "/c/temp/ruby/retry.rb", 10, :to_s, #<Binding:0x100f4eb8>,
Fixnum]
["c-call", "/c/temp/ruby/retry.rb", 10, :write, #<Binding:0x100f4e70>, IO]
0["c-return", "/c/temp/ruby/retry.rb", 10, :write, #<Binding:0x100f4d50>,
IO]
["c-call", "/c/temp/ruby/retry.rb", 10, :write, #<Binding:0x100f4c30>, IO]
["c-return", "/c/temp/ruby/retry.rb", 10, :write, #<Binding:0x100f4b10>,
IO]
["c-return", "/c/temp/ruby/retry.rb", 10, :puts, #<Binding:0x100f49f0>,
Kernel]
["line", "/c/temp/ruby/retry.rb", 11, nil, #<Binding:0x100f48d0>, false]
["c-call", "/c/temp/ruby/retry.rb", 11, :+, #<Binding:0x100f47b0>, Fixnum]
["c-return", "/c/temp/ruby/retry.rb", 11, :+, #<Binding:0x100f4690>,
Fixnum]
["line", "/c/temp/ruby/retry.rb", 5, :repeat, #<Binding:0x100f4570>,
Object]
["line", "/c/temp/ruby/retry.rb", 5, :repeat, #<Binding:0x100f4450>,
Object]
["return", "/c/temp/ruby/retry.rb", 3, :repeat, #<Binding:0x100f4330>,
Object]
["c-call", "/c/temp/ruby/retry.rb", 9, :>=, #<Binding:0x100f4210>, Fixnum]
["c-return", "/c/temp/ruby/retry.rb", 9, :>=, #<Binding:0x100f40f0>,
Fixnum]
["call", "/c/temp/ruby/retry.rb", 2, :repeat, #<Binding:0x100f3ee0>,
Object]
["line", "/c/temp/ruby/retry.rb", 3, :repeat, #<Binding:0x100f3e98>,
Object]
["c-call", "/c/temp/ruby/retry.rb", 3, :to_s, nil, FalseClass]
["c-return", "/c/temp/ruby/retry.rb", 3, :to_s, nil, FalseClass]
["c-call", "/c/temp/ruby/retry.rb", 3, :puts, #<Binding:0x100f3b38>,
Kernel]
["c-call", "/c/temp/ruby/retry.rb", 3, :write, #<Binding:0x100f3a18>, IO]
condition: false["c-return", "/c/temp/ruby/retry.rb", 3, :write,
#<Binding:0x100f38f8>, IO]
....
You see that it goes back to line 9 reevaluating the >=. If you ask why
this is (i.e. design rationale), you probably have to ask Matz. :-) HTH
Kind regards
robert