Issue #7545 has been updated by alexeymuranov (Alexey Muranov).


drbrain (Eric Hodel) wrote:
> alexeymuranov (Alexey Muranov) wrote:
> > I propose the range to store a lazy ordered set,
> 
> Range is lazy today.

But it is not a set, it seems to be just a pair of bounds, like a 2-element array. I propose to change the semantic, and hence behavior in applications like `Array#slice`.

> > which is normally an interval in some bigger ordered set.  I have not specified an implementation, but for example it can store the bounds, unless the set is empty, and some kind of identifiers for the ambient set and for the order used. Probably this will have little in common with the current implementation.
> 
> If no bounds are stored for an empty set and you can't tell the difference between (1???1) and (3???3) what should Range#inspect do?

Just print that it is the empty range.  I suggested a constant name `Range::EMPTY_SET`

> What is an ambient set?

I meant that to store 1..3 or 3..1 or 1...(3.5), it is enough to store the bounds, assume that the the interval is a subset of the reals (so that floats, rationals, and others could be tested for inclusion,  for 'a'..'c' the natural ambient set would be the set of words), and remember the order (the usual or the reverse).

> Why is such a big change necessary?

This would make the Range class quite intelligent.  I do not know if it is necessary.

> > As 3 and 1 are integers and 3 > 1, i propose to interpret the literal `3..1` as an interval in the set of integers, with the lower bound 3, the upper bound 1, and the order reverse to the usual order (3 < 2 < 1), designated by a symbol `:rev` for example.  I would propose to delegate the responsibility of converting `3..1` to an array to the `Integer` class (allowing also the explicit syntax `(3..1).to_a(Integer)`).  The `Integer` class should know how to iterate over a range when the bounds and the order (direction) are given.
> 
> What is ":rev"? Revision? Reverse? Revise?

I meant reverse order, it was just an example.

> Range and Set are different concepts (and classes). I don't see why you would define equality on Set based on some other class (Array, here). This is not good OO design.

`Set` class only works to store finite sets, while `Range` class can be used to represent infinite sets, like the intervals [0, ???), or [0, 1] (there are infinitely many reals or rationals in both).

For the equality of 1...1 and 3...3, i meant that they both model the same object: the empty set, this was the actual reason.

> > I did not talk about `#cover?` in this proposal, but in my opinion having both is redundant, i would prefer having just `#include?`, possibly with some options.
> 
> How does this fit with existing implementations of #include?

I do not know. I was thinking about an abstraction of `Range` class.
----------------------------------------
Feature #7545: Make Range act as a "lazy ordered set"
https://bugs.ruby-lang.org/issues/7545#change-34634

Author: alexeymuranov (Alexey Muranov)
Status: Open
Priority: Normal
Assignee: 
Category: core
Target version: Next Major


=begin
# Make Range act as a "lazy ordered set"

This replaces my older feature request #5534.

I propose the following new behavior of (({Range})):

  (1..3).to_a               # => [1, 2, 3]
  (3..1).to_a               # => [3, 2, 1]
  'a'..'c'.to_a             # => ['a', 'b', 'c']
  'c'..'a'.to_a             # => ['c', 'b', 'a']
  1...1 == 3...3            # => true
  1...1 == 'a'...'a'        # => true
  1...1 == Range::EMPTY_SET # => true
  1..2 == 1...3             # => false
  1...3.include?(2.5)       # => true

Also, maybe in the future the following behavior can be possible:

  r1 = Range.new('a', 'bc', :deglex)
  r1.include?('abc') # => false
  r1.to_a            # => ['a', 'b', ..., 'az', 'ba', 'bb', 'bc']
  r2 = Range.new('a', 'bc', :lex)
  r2.include?('abc') # => true
  r2.to_a            # => Error

and this:

  ((0.5)..(5.5)).to_a(Integer) # => [1, 2, 3, 4, 5]
  ((0.5)..(5.5)).each(Integer) do |i| puts i end

(i imagine this would require additions to the (({Integer})) class, so that it
know more about "real" ranges).


=end



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