Issue #5534 has been updated by Thomas Sawyer.


"There are infinitely many numbers, even if you only count rationals, in the range (1..2)"

Ah, okay. See, I think that's a good case in point. I was thinking of range as a sequence, while you were thinking of it an interval.

Well, I think the only good thing about the multi-purpose Range is that we only need one literal notation, ie. `x..y`. Otherwise I think it would probably be better to have a separate Interval class, if only for the fact that Range, unlike an actual interval, can't exclude the starting sentinel. But other methods would likely vary too, as some of your comments make clear, such as #==.

In addition there are a lot of short-cuts taken when dealing with Ranges. If for instance we create an EvenInt class as subclass of Integer that could only represent even integers. Then...

<pre>
  r = (EvenInt[2]...EvenInt[4])
</pre>

This range will not actually behave as we expect in all cases.

<pre>
 r.to_a          #=> [2,4]
 [0,1,2,3,4][r]  #=> [2,3,4]
 r.include?(3)   #=> true
</pre>

----------------------------------------
Feature #5534: Redefine Range class and introduce RelativeNumeric and RelativeRange
http://redmine.ruby-lang.org/issues/5534

Author: Alexey Muranov
Status: Open
Priority: Normal
Assignee: 
Category: core
Target version: 


I started by commenting on Feature #4541, but ended up with proposing a new feature myself.

I suggest to redefine the behavior of Range class so that all empty ranges be equal:

(2..1) == (1..-1) and (2..1) == (1...1) and (2..1) == ('z'..'a') # => true

In other fords, ranges `r1` and `r2` should be equal if and only if `r1.include?` and `r2.include?` give identical results for all inputs.  (Why is it not `includes?` by the way?)  Thus Range would simply be a way to store certain infinite sets.

This change will result in not being able to slice an array `a` from beginning and from the end simultaneously with `a[1..-2]`. To resolve this, i propose to introduce `RelativeNumeric` and `RelativeRange` classes.

Each `RelativeNumeric` would be a `Numeric` with an "anchor", which is an arbitrary symbol.  For example:

3.from(:bottom)  # would return a "relative" 3 with "anchor" :bottom

One can define shortcuts `#from_bottom` for `#from(:bottom)` and `#from_top` for `#from_top`.

A `RelativeRange` is a range with relative bounds.  If bounds of a relative range r are relative to the same anchor and the range is seen to be empty, it should be equal to *the* empty relative range with this anchor.  For example:

(3.from(:center)..2.from(:center)) == (0.from(:center)...0.from(:center)) # => true

Now, to do what is currently done by `a[1..-2]`, one can redefine `Array#slice` to use instead:

a[1.from_bottom..(-1).from_top]

What do you think?



-- 
http://redmine.ruby-lang.org