Issue #5534 has been updated by Thomas Sawyer.


"This way it would be clear what a range is --- just an infinite set of a certain form, with methods to work with it."

How is that a Range at all? A Range is only "infinite" if one of the sentinels is infinite.

"Mathematically, ranges (2..1) et (3..0) are equal --- both empty, but Ruby remembers their "bounds" and treats them differently."

How is a Range to work without remembering the bounds?

If anything I wish Ruby would understand "counting down" ranges. Currently `(3..1).to_a` returns `[]`.

"x == y  must be true if and only if  x.include?(z) == y.include?(z)  is true for every possible object  z."

For better or worse, Range serves a double (perhaps triple) purpose, e.g. it can serve as interval or it can serve as a way to define a sequential set. So the meaning of #== might not be considered that same in these cases. So Range was given a general definition that works for who it is designed --based on the range bounds. To do as you suggest would, I thing require separating Range into Interval and Sequence classes, so to speak, where you definition of #== is more fitting a Sequence, albeit one might still argument that the order of sequence should be significant too.




----------------------------------------
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