Robert Klemme <bob.news / gmx.net> wrote:

>> Interesting.  I would lean towards (b) (which I believe is the current
>> implementation if exclude_end? is false).
>
> In that case the inclusion of Enumerable becomes questionable.

But Ranges have many other uses which depend on it being Enumerable

>> (a) is not really practical because Range is not always Enumerable and
>> this also conflicts with my mental model of a "Range"
>
> Right:
>
>>> (1.5 .. 3.4).to_a
> TypeError: cannot iterate from Float
>         from (irb):14:in `each'
>         from (irb):14:in `to_a'
>         from (irb):14
>
> We have the weired situation that a Range where left and right are  
> enumerable (integers, strings) the inclusion of Enumerable is ok and for

A range is only Enumerable if the left side defines +succ+

   >> (0..Math::PI).to_a
   => [0, 1, 2, 3]
   >> class Float; def succ; self+0.8; end; end;
   => nil
   >> (0.1..2.0).to_a
   => [0.1, 0.9, 1.7]

> non enumerable types (Float) it's not.  That's a bit weired situation  
> IMHO, at least not exactly good design.

I don't believe that it is much of a problem in practice.

Maybe Range should have a method enumerable? so that you can check if each  
is going to work before you actually use it.

   class Range
     def enumerable?
       first.respond_to?(:succ)
     end
   end

   r = (1..10)
   arr = r.enumerable? ? r.entries : []

-Levin