From: Christoph Date: 2002-05-07T06:34:39+09:00 Subject: Re: Fixes for the new step methods in the range.c & numeric.c "Yukihiro Matsumoto" wrote in message news:1020698891.267211.31121.nullmailer@picachu.netlab.jp... > Hi, > > In message "Re: Fixes for the new step methods in the range.c & numeric.c" > on 02/05/07, Yukihiro Matsumoto writes: > > I guess the patches need a better explanation. Here is the rational for the range.c patch. The problem with the current implementation of the (generic) Range#step method is that it performs an unchecked #succ iteration. This potential ``overshooting'' of the end point of a Range object causes two types of problems. A ``comparison failure'' or ``#succ iteration failure''. --- # Ruby version of the patch class Range def generic_step(k) curr = first # guard against overshooting n = k while curr < last if n == k yield curr n = 1 else n+= 1 end curr = curr.succ end if !exclude_end? and n == k yield curr end self end end # Use the example of Ruby's Class Tree class Class alias succ superclass end curr = Object ('A'..'F').each do |klass| curr = Object.const_set klass,Class.new(curr) end puts (F..Object).to_a.join " < " (F..Object).generic_step(3) {|klass| p klass } puts "\n" (F..Object).generic_step(2) {|klass| p klass } --- this results in --- F < E < D < C < B < A < Object F C Object F D B Object --- The current (=cvs) step method implements the following strategy. --- module Kernel def iterate(meth,k) curr = self k.times do |i| begin curr = curr.send(meth) rescue raise ArgumentError.new \ "you can iterate #{self} with ##{meth.to_s} at most #{i}-times" end end curr end end class Range def generic_step(k) curr = first unless exclude_end? # this might throw an ex while curr <= last yield curr curr = curr.iterate(:succ,k) end else while curr < last yield curr curr = curr.iterate(:succ,k) end end self end end class Class alias succ superclass end curr = Object ('A'..'E').each do |klass| curr = Object.const_set klass,Class.new(curr) end begin puts "comparison failure" (E..Object).generic_step(2) {|klass| p klass } rescue => mes puts mes end begin puts "\n","succ iteration failure" (E..Object).generic_step(4) {|klass| p klass } rescue => mes puts mes end --- resulting in --- comparison failure E C A undefined method `<=' for nil succ iteration failure E A you can iterate A with #succ at most 2-times --- /Christoph