From: Robert Klemme Date: 2006-02-07T20:23:22+09:00 Subject: Re: lazy evaluation? ------=_NextPart_000_0012_01C62BE0.EB012FB0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit 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, #, false] ["line", "/c/temp/ruby/retry.rb", 9, nil, #, false] ["c-call", "/c/temp/ruby/retry.rb", 9, :>=, #, Fixnum] ["c-return", "/c/temp/ruby/retry.rb", 9, :>=, #, Fixnum] ["call", "/c/temp/ruby/retry.rb", 2, :repeat, #, Object] ["line", "/c/temp/ruby/retry.rb", 3, :repeat, #, 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, #, Kernel] ["c-call", "/c/temp/ruby/retry.rb", 3, :write, #, IO] condition: false["c-return", "/c/temp/ruby/retry.rb", 3, :write, #, IO] ["c-call", "/c/temp/ruby/retry.rb", 3, :write, #, IO] ["c-return", "/c/temp/ruby/retry.rb", 3, :write, #, IO] ["c-return", "/c/temp/ruby/retry.rb", 3, :puts, #, Kernel] ["line", "/c/temp/ruby/retry.rb", 4, :repeat, #, Object] ["line", "/c/temp/ruby/retry.rb", 10, nil, #, false] ["c-call", "/c/temp/ruby/retry.rb", 10, :puts, #, Kernel] ["c-call", "/c/temp/ruby/retry.rb", 10, :to_s, #, Fixnum] ["c-return", "/c/temp/ruby/retry.rb", 10, :to_s, #, Fixnum] ["c-call", "/c/temp/ruby/retry.rb", 10, :write, #, IO] 0["c-return", "/c/temp/ruby/retry.rb", 10, :write, #, IO] ["c-call", "/c/temp/ruby/retry.rb", 10, :write, #, IO] ["c-return", "/c/temp/ruby/retry.rb", 10, :write, #, IO] ["c-return", "/c/temp/ruby/retry.rb", 10, :puts, #, Kernel] ["line", "/c/temp/ruby/retry.rb", 11, nil, #, false] ["c-call", "/c/temp/ruby/retry.rb", 11, :+, #, Fixnum] ["c-return", "/c/temp/ruby/retry.rb", 11, :+, #, Fixnum] ["line", "/c/temp/ruby/retry.rb", 5, :repeat, #, Object] ["line", "/c/temp/ruby/retry.rb", 5, :repeat, #, Object] ["return", "/c/temp/ruby/retry.rb", 3, :repeat, #, Object] ["c-call", "/c/temp/ruby/retry.rb", 9, :>=, #, Fixnum] ["c-return", "/c/temp/ruby/retry.rb", 9, :>=, #, Fixnum] ["call", "/c/temp/ruby/retry.rb", 2, :repeat, #, Object] ["line", "/c/temp/ruby/retry.rb", 3, :repeat, #, 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, #, Kernel] ["c-call", "/c/temp/ruby/retry.rb", 3, :write, #, IO] condition: false["c-return", "/c/temp/ruby/retry.rb", 3, :write, #, 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 ------=_NextPart_000_0012_01C62BE0.EB012FB0 Content-Type: application/octet-stream; name="retry.rb" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="retry.rb" #!/usr/bin/env ruby=0A= def repeat(condition)=0A= puts "condition: #{condition}"=0A= yield=0A= retry if not condition=0A= end=0A= set_trace_func lambda {|*a| p a}=0A= j=3D0=0A= repeat (j >=3D 5) do=0A= puts j=0A= j+=3D1=0A= end=0A= ------=_NextPart_000_0012_01C62BE0.EB012FB0--