Range relies entirely on Enumerable to implement #min and #max, which
in turn implements these operations using #to_a. This becomes a
problem with ranges of floats, for example:
(0.0…100.0).min
TypeError: can’t iterate from Float
from (irb):9:in `each’
from (irb):9
from :0
Not to mention that it becomes inefficient to expand the whole range
into array, such as for very large integers:
(0.0…2**128).min
(Tends to run out of memory.)
I think it makes more sense to implement these operations in terms of
<=>, like so:
class Range
def min
(self.first <=> self.last) <= 0 ? self.first : nil
end
def max
(self.first <=> self.last) <= 0 ? self.last : nil
end
end
I don’t see any reason to rely on expanding the range using
Enumerable#to_a, since the operations can be implemented purely in
terms of the range boundaries.
I would be happy to submit a patch.
Alexander.
Hi,
In message “Re: Improving min/max for Range”
on Fri, 25 Nov 2005 09:30:39 +0900, Alexander
[email protected] writes:
|I think it makes more sense to implement these operations in terms of
|<=>, like so:
#min makes sense. I’d like to merge your idea. #max needs to
consider about end exclusion. I’m not sure what (0…1.0).max should
return. Error?
matz.
On 11/25/05, Yukihiro M. [email protected] wrote:
return. Error?
matz.
Good point. I think max should throw if the number doesn’t support the
integer protocol; there’s simply no way to handle it intelligently.
For int-type types, I suggest that (end.to_int - 1) should be used,
since there is no #pred counterpart to #succ.
Alexander.
On 11/25/05, Yukihiro M. [email protected] wrote:
|Good point. I think max should throw if the number doesn’t support the
|integer protocol; there’s simply no way to handle it intelligently.
|For int-type types, I suggest that (end.to_int - 1) should be used,
|since there is no #pred counterpart to #succ.
I’ve just committed my implementation of Range#min and #max to CVS
HEAD. Check if you have interest.
matz.
I see you decided to return nil instead of throwing; acceptable, I
suppose. More sneaky is how you let Enumerable handle the case when
the end is excluded – I would have preferred to do that only do if
#end was not an integer.
Here’s a unit test patch, btw:
diff -u -r1.5 test_range.rb
— test/ruby/test_range.rb 5 Aug 2005 23:56:02 -0000 1.5
+++ test/ruby/test_range.rb 25 Nov 2005 02:47:06 -0000
@@ -31,4 +31,24 @@
def test_duckrange
assert_equal(“bc”, “abcd”[DuckRange.new(1,2)])
end
+
- def test_min
- assert_equal(1, (1…2).min)
- assert_equal(nil, (2…1).min)
- assert_equal(1, (1…2).min)
-
- assert_equal(1.0, (1.0…2.0).min)
- assert_equal(nil, (2.0…1.0).min)
- assert_equal(1, (1.0…2.0).min)
- end
-
- def test_max
- assert_equal(2, (1…2).max)
- assert_equal(nil, (2…1).max)
- assert_equal(1, (1…2).max)
-
- assert_equal(2.0, (1.0…2.0).max)
- assert_equal(nil, (2.0…1.0).max)
- assert_raise(TypeError) { (1.0…2.0).max }
- end
end
Alexander.
Hi,
In message “Re: Improving min/max for Range”
on Fri, 25 Nov 2005 10:53:35 +0900, Alexander
[email protected] writes:
|> #min makes sense. I’d like to merge your idea. #max needs to
|> consider about end exclusion. I’m not sure what (0…1.0).max should
|> return. Error?
|Good point. I think max should throw if the number doesn’t support the
|integer protocol; there’s simply no way to handle it intelligently.
|For int-type types, I suggest that (end.to_int - 1) should be used,
|since there is no #pred counterpart to #succ.
I’ve just committed my implementation of Range#min and #max to CVS
HEAD. Check if you have interest.
matz.
Hi,
In message “Re: Improving min/max for Range”
on Fri, 25 Nov 2005 11:51:30 +0900, Alexander
[email protected] writes:
|I see you decided to return nil instead of throwing; acceptable, I
|suppose. More sneaky is how you let Enumerable handle the case when
|the end is excluded – I would have preferred to do that only do if
|#end was not an integer.
Sounds reasonable. Can you check my new modify?
|Here’s a unit test patch, btw:
Thank you. It’s merged.
matz.
On 11/25/05, Yukihiro M. [email protected] wrote:
Sounds reasonable. Can you check my new modify?
Great, that works. Thanks.
Alexander.