Ruby Range issues

R

Ray Bovet

[Note: parts of this message were removed to make it a legal post.]

Since I haven't posted to this group in the past 5 years or so, let me
start by saying how much I enjoy using Ruby! My comments below reflect
my desire to see a couple of small issues improved in this extraordinary
language!


The first is a requested feature (which works in 1.8.7 but not in
1.9.2p136), while the second appears to me to be a bug that exists in
both 1.8.7 and 1.9.2:

1. Range.step says (per PickAxe 3) that it works with range elements
that support .succ, or with numbers. It would be nice to have it work
with elements that support .succ, /or with elements that support adding
a number to them/. This would allow stepping through time ranges, for
example.

2. Range.step where the end is specified to be excluded ( '...') on
floats seems to exclude the last value that should be included. For
example:
( 1.0 ... 5.01).step( 2) {|x| puts x}
outputs 1.0 and 3.0 but not 5.0.
Interestingly, ( 1.0 ... 5.01).cover?( 5.0) returns true, as it should!

*Ray Bovet*
**
 
R

Robert Klemme

Since I haven't posted to this group in the past 5 years or so, let me st= art
by saying how much I enjoy using Ruby! =A0My comments below reflect my de= sire
to see a couple of small issues improved in this extraordinary language!


The first is a requested feature (which works in 1.8.7 but not in
1.9.2p136), while the second appears to me to be a bug that exists in bot= h
1.8.7 and 1.9.2:

1. Range.step says (per PickAxe 3) that it works with range elements that
support .succ, or with numbers. =A0It would be nice to have it work with
elements that support .succ, /or with elements that support adding a numb= er
to them/. =A0This would allow stepping through time ranges, for example.

Not sure this is a good idea. After all, if +1 would be the "default"
increment for a class #succ would have been implemented that way. In
absence of a #succ implementation a Range cannot do any assumption as
to how get the next value - that's the exact reason why there is a
method #succ. You could as well wrap a Time instance in something
that implements #succ accordingly.

irb(main):001:0> require 'delegate'
=3D> true
irb(main):002:0> class TD < SimpleDelegator
irb(main):003:1> def succ;self.class.new(__getobj__ + 1); end
irb(main):004:1> end
=3D> nil
irb(main):005:0> t =3D TD.new(Time.now)
=3D> 2011-02-01 16:23:24 +0100
irb(main):006:0> t.succ
=3D> 2011-02-01 16:23:25 +0100
irb(main):007:0> t.succ.succ
=3D> 2011-02-01 16:23:26 +0100
2. Range.step where the end is specified to be excluded ( '...') on float= s
seems to exclude the last value that should be included. =A0For example:
=A0 =A0( 1.0 ... 5.01).step( 2) {|x| puts x}
=A0 =A0outputs 1.0 and 3.0 but not 5.0.
=A0 =A0Interestingly, ( 1.0 ... 5.01).cover?( 5.0) returns true, as it sh=
ould!

Sounds like a bug which is not present in 1.9.2:

irb(main):008:0> (1.0..5.1).step(2).to_a
=3D> [1.0, 3.0, 5.0]
irb(main):009:0> (1.0..5.01).step(2).to_a
=3D> [1.0, 3.0, 5.0]

Cheers

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
R

Ray Bovet

[Note: parts of this message were removed to make it a legal post.]

Thanks for the comments, Robert.

I agree that .succ for a Time is not obvious (there actually *is* a .succ
method for Time in 1.9.2 although it reports that it is deprecated), but I'd
still like to be able to use a specific step value. It may be that your
wrapping suggestion is the best way forward, but I would think a lot of
people might want to be able to step through time intervals.

On the second issue, you only show the results with two dots. What I was
concerned about was when you use three dots in order to exclude the endpoint
of the range. In both 1.8.7 and 1.9.2p136 you only get 1.0 and 3.0. It
appears that it first converts the end points to Integer before doing the
end comparison. Here's an example in 1.9.2 showing both the 2 dot and the 3
dot versions:

irb
ruby-1.9.2-p136 :001 > ( 1.0 .. 5.01).step(2).to_a
=> [1.0, 3.0, 5.0]
ruby-1.9.2-p136 :002 > ( 1.0 ... 5.01).step(2).to_a
=> [1.0, 3.0]
 
B

Brian Candler

The logic is in ruby_float_step in float.c.

It doesn't do the obvious (add step to base until exceed maximum),
probably to avoid accumulating errors. But I think the logic is wrong
for the ... case.

if (!excl) n++;
for (i=0; i<n; i++) {
rb_yield(DBL2NUM(i*unit+beg));
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,234
Latest member
SkyeWeems

Latest Threads

Top