Forum: Ruby Range#member? Oddity

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-13 21:50
(Received via mailing list)
I'm not understanding what I am seeing here.  Can anyone please
explain why the last line of this session gives *false* as an answer?

 >> range = ("1".."10")
=> "1".."10"
 >> range.to_a
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
 >> range.member?("1")
=> true
 >> range.member?("2")
=> false

James Edward Gray II
F3b7b8756d0c7f71cc7460cc33aefaee?d=identicon&s=25 Daniel Berger (Guest)
on 2006-01-13 21:56
(Received via mailing list)
James Edward Gray II wrote:
> => false
>
> James Edward Gray II

I cannot duplicate this with 1.8.2 or 1.8.4.

- Dan
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-13 21:59
(Received via mailing list)
On Jan 13, 2006, at 2:54 PM, Daniel Berger wrote:

>> => false
>> James Edward Gray II
>
> I cannot duplicate this with 1.8.2 or 1.8.4.

Odd.  I'm using 1.8.4:

$ ruby -v
ruby 1.8.4 (2005-12-24) [powerpc-darwin8.3.0]

James Edward Gray II
F3b7109c91841c7106784d229418f5dd?d=identicon&s=25 Justin Collins (Guest)
on 2006-01-13 21:59
(Received via mailing list)
It happens in 1.8.2 for me. It shows "1" and "10" as being in the range,
but nothing else.

[justinc@justinc-dsktp ~]$ ruby -v
ruby 1.8.2 (2004-12-25) [i586-linux-gnu]
[justinc@justinc-dsktp ~]$ irb
irb(main):001:0> range = ("1".."10")
=> "1".."10"
irb(main):002:0> range.to_a
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
irb(main):003:0> range.member?("1")
=> true
irb(main):004:0> range.member?("2")
=> false
irb(main):005:0> range.member?("10")
=> true
irb(main):006:0>


Note that range _isn't_ getting converted into an array.

-Justin
9358cc96c46055cd68d4a76a9aefe026?d=identicon&s=25 Daniel Harple (Guest)
on 2006-01-13 22:02
(Received via mailing list)
Daniel Berger wrote:
> James Edward Gray II wrote:
>> I'm not understanding what I am seeing here.  Can anyone please
>> explain why the last line of this session gives *false* as an answer?
>> <snip>
>
> I cannot duplicate this with 1.8.2 or 1.8.4.
>
> - Dan

I'm getting this too. 1 and 10 both return true, everything else
returns false.

$ ruby -v
ruby 1.8.4 (2005-12-24) [powerpc-darwin8.3.0]
Ace7fa5337acbdf5897a6fc035897580?d=identicon&s=25 J. Ryan Sobol (Guest)
on 2006-01-13 22:05
(Received via mailing list)
On Jan 13, 2006, at 3:54 PM, Daniel Berger wrote:

>> => false
>> James Edward Gray II
>
> I cannot duplicate this with 1.8.2 or 1.8.4.

I can.

$ ruby -v
ruby 1.8.4 (2005-12-24) [powerpc-darwin8.3.0]

~ ryan ~
2af5f7d824822ccf9304b670cc3ce984?d=identicon&s=25 tokmak tokmak (Guest)
on 2006-01-13 22:05
(Received via mailing list)
it gets odder:

irb(main):001:0> range = ("1".."10")
=> "1".."10"
irb(main):002:0> range.to_a
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
irb(main):003:0> range.member?("1")
=> true
irb(main):004:0> range.member?("2")
=> false
irb(main):005:0> range.member?("4")
=> false
irb(main):006:0> range.member?("9")
=> false
irb(main):007:0> range.member?("10")
=> true
irb(main):008:0> range.include?("2")
=> false
irb(main):009:0> range.include?("1")
=> true
irb(main):010:0> range === "1"
=> true
irb(main):011:0> range === "2"
=> false
irb(main):012:0> RUBY_VERSION
=> "1.8.2"


2006/1/13, James Edward Gray II <james@grayproductions.net>:
F3b7b8756d0c7f71cc7460cc33aefaee?d=identicon&s=25 Daniel Berger (Guest)
on 2006-01-13 22:08
(Received via mailing list)
James Edward Gray II wrote:
>>>  >> range.member?("1")
>
> $ ruby -v
> ruby 1.8.4 (2005-12-24) [powerpc-darwin8.3.0]
>
> James Edward Gray II
>

Whoops, I misspoke.  I was using numbers, not strings.  I do, in fact,
get the
same behavior in 1.8.4 (and 1.8.2).

/me guesses randomly that it has something to do with stringified
numbers in
particular.

Regards,

Dan
E997cf907c21c66a6ca2e1e78cd8ebea?d=identicon&s=25 Dan Hinz (Guest)
on 2006-01-13 22:11
(Received via mailing list)
I don't know for sure but my guess has something to do with numbers vs
characters and whether "1".."10" expands to the same thing that 1..10
does.

>>range=(1..10)
1..10
>>range.member?(1)
true
>>range.member?(2)
true
>>range.member?(3)
true
>>puts range
1..10

   Huh???

-dwh-

On Fri, 2006-01-13 at 16:01, Daniel Harple wrote:

> I'm getting this too. 1 and 10 both return true, everything else
> returns false.
>
> $ ruby -v
> ruby 1.8.4 (2005-12-24) [powerpc-darwin8.3.0]

--
I not only live each endless day in grief, but live each day
thinking about living each day in grief.
                                              -- C.S. Lewis

Daniel W. Hinz         Xerox Corp: XOG/SEBU/MCD/EIDC/ISM&D
MS: 111-03J            e-mail:      dhinz@eng.mc.xerox.com
800 Phillips Road     TEL:          585.422.8078
Webster, NY 14580
0817571d150afead454f4220007042fe?d=identicon&s=25 Matthew Desmarais (Guest)
on 2006-01-13 22:18
(Received via mailing list)
James Edward Gray II wrote:
> => false
>
> James Edward Gray II
>
>
>
Hi,

There was some discussion about this in the recent past.  If my memory
serves me right (certainly an infrequent happening), the issue that
you're running into is that Range#member?  is implemented as:
class Range
    def member?(val)
       if self.exclude_end?
           (self.first <= val) and (val < self.last)
       else
          (self.first <= val) and (val <= self.last)
       end
    end
end

You should find this in both 1.8.2 and 1.8.4 I think.

There's a previous thread on ruby-talk about it, here's a link to
somewhere near the conclusion of the discussion:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...

Matthew
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-13 22:30
(Received via mailing list)
On Jan 13, 2006, at 3:16 PM, Matthew Desmarais wrote:

> There's a previous thread on ruby-talk about it, here's a link to
> somewhere near the conclusion of the discussion:
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...

This cleared it up for me.  Thank you.

I was aware of the old system, where member?() and include?() had
separate meanings and just didn't know it had been abandoned.

James Edward Gray II
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-13 23:01
(Received via mailing list)
On Fri, 13 Jan 2006 22:16:14 +0100, Matthew Desmarais
<desmarm@gmail.com>
wrote:

>> >> range.member?("2")
> you're running into is that Range#member?  is implemented as:
> You should find this in both 1.8.2 and 1.8.4 I think.
>
> There's a previous thread on ruby-talk about it, here's a link to
> somewhere near the conclusion of the discussion:
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...
>
> Matthew
>


This would seem to make it an oddity of String#succ, that behaving
automagically, not generating successors with respect to String
comparison.

E.g. for any Integers i, i.succ > i. For some strings, that does't hold
true.

Bottom line: Don't use strings when you're really using numbers. Like in
mathemathical contexts. D'oh. You could possibly hack around that in
Range
code to provide for data types where generating successors is
inconsistent
with comparison, but I wouldn't like to see that.

David Vallner
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-13 23:01
(Received via mailing list)
On Jan 13, 2006, at 3:58 PM, David Vallner wrote:

> You could possibly hack around that in Range code to provide for
> data types where generating successors is inconsistent with
> comparison, but I wouldn't like to see that.

It's not too tough in this case:

 >> ("1".."10").to_a.include?("2")
=> true

James Edward Gray II
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-13 23:16
(Received via mailing list)
On Fri, 13 Jan 2006 23:00:37 +0100, James Edward Gray II
<james@grayproductions.net> wrote:

>
> James Edward Gray II
>


Yes, that always works, but it beats the point of having first class
ranges as opposed to just having a pythonesque range function in the
first
place. I'd personally rather coerce the strings to numbers if I know
they
represent such to get more type safety and possibly some execution speed
too.

David Vallner
Ace7fa5337acbdf5897a6fc035897580?d=identicon&s=25 J. Ryan Sobol (Guest)
on 2006-01-13 23:49
(Received via mailing list)
The rdoc needs to be updated for Range#include? and Range#member? then.

~ ryan ~
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 00:04
(Received via mailing list)
No, those methods work perfectly. The behaviour of String is the problem
here.

On Fri, 13 Jan 2006 23:46:26 +0100, J. Ryan Sobol <ryansobol@gmail.com>
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-14 00:19
(Received via mailing list)
On Jan 13, 2006, at 5:04 PM, David Vallner wrote:

> No, those methods work perfectly. The behaviour of String is the
> problem here.

???  How exactly is it that you believe String should behave?

James Edward Gray II
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 00:55
(Received via mailing list)
On Sat, 14 Jan 2006 00:17:26 +0100, James Edward Gray II
<james@grayproductions.net> wrote:

> On Jan 13, 2006, at 5:04 PM, David Vallner wrote:
>
>> No, those methods work perfectly. The behaviour of String is the
>> problem here.
>
> ???  How exactly is it that you believe String should behave?
>
> James Edward Gray II
>


Well, to work well in Ranges, for any String s, s.succ > s must hold
true.

David Vallner
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-14 01:01
(Received via mailing list)
On Jan 13, 2006, at 5:54 PM, David Vallner wrote:

>> James Edward Gray II
>>
>
>
> Well, to work well in Ranges, for any String s, s.succ > s must
> hold true.

I'm pretty sure we don't want to change the meaning of String
comparisons at this point.  succ() just doesn't happened to be
defined under those terms, because then it would be a lot less useful
to us.  It's hard for me to see any of that as "broken".

James Edward Gray II
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-01-14 01:20
(Received via mailing list)
On Jan 13, 2006, at 6:54 PM, David Vallner wrote:
> Well, to work well in Ranges, for any String s, s.succ > s must
> hold true.

How about having Range use Object#strict_succ to generate
its sequence?  Define String#strict_succ as needed to guarantee
s.succ > s and then alias strict_succ to succ for other classes
(such as Fixnum) so they don't break when used in a Range.


Gary Wright
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-01-14 01:29
(Received via mailing list)
On Jan 13, 2006, at 7:18 PM, gwtmp01@mac.com wrote:

>
> Gary Wright
>
>
>
>

This seems to me to make the problem worse. People expect the values
generated by String#succ to be in the array when doing a to_a for
instance. I believe the real solution would be to bring back the
distinction between member and include (possibly with a new name for
the method with the functionality of #member).
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 01:35
(Received via mailing list)
On Sat, 14 Jan 2006 01:01:21 +0100, James Edward Gray II
<james@grayproductions.net> wrote:

> On Jan 13, 2006, at 5:54 PM, David Vallner wrote:
>
> I'm pretty sure we don't want to change the meaning of String
> comparisons at this point.  succ() just doesn't happened to be defined
> under those terms, because then it would be a lot less useful to us.
> It's hard for me to see any of that as "broken".
>
> James Edward Gray II
>


I never said anything the like, the code breakage would be inexcusable.

My point is it's String that behaves erreneously in this context and
isn't
suitable for use in symbolic ranges, not a bug in Range code - the posts
were an objection to people wanting to mess up the Range interface.

David Vallner
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 01:38
(Received via mailing list)
On Sat, 14 Jan 2006 01:26:22 +0100, Logan Capaldo
<logancapaldo@gmail.com>
wrote:

>> s.succ > s and then alias strict_succ to succ for other classes
> generated by String#succ to be in the array when doing a to_a for
> instance. I believe the real solution would be to bring back the
> distinction between member and include (possibly with a new name for the
> method with the functionality of #member).
>


I agree that the change proposed would break Range#to_a for strings,
which
I can imagine being used. The real solution would be people coding
sanely
and using Integers to represent integers, and Strings to represent text
-
using unsuitable data types resulting in a bug is arguably not a
language
fault.

David Vallner
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-01-14 01:56
(Received via mailing list)
On Jan 13, 2006, at 7:26 PM, Logan Capaldo wrote:
> This seems to me to make the problem worse. People expect the
> values generated by String#succ to be in the array when doing a
> to_a for instance. I believe the real solution would be to bring
> back the distinction between member and include (possibly with a
> new name for the method with the functionality of #member).

It seems strange to want Range to behave like an interval and to
also want Range#to_a to create a list of elements that don't all
belong in that same interval.

I understand the desire to generate a sequence of strings
as defined by the current behavior of String#succ but I don't understand
why you would want to use a Range object as a shortcut to that sequence.
That particular sequence really has nothing to do with an interval
or the ordering defined by String#<=>


Gary Wright
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 02:05
(Received via mailing list)
On Sat, 14 Jan 2006 01:53:37 +0100, <gwtmp01@mac.com> wrote:

>
> It seems strange to want Range to behave like an interval and to
> also want Range#to_a to create a list of elements that don't all
> belong in that same interval.

It's a Convenient Hack (tm), and those are extremely hard to weed out
once
they catch hold. It's the same as when people use #eval that must a
nightmare to the brave folks working on optimizing YARV (I want my clean
blocks!) instead of the much cleaner metaprogramming facilities in Ruby
that let you achieve 99% of what I've seen hacked with evals anyway.
(Very
obfuscated eval hacks notwithstanding).

David Vallner
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-01-14 02:38
(Received via mailing list)
On Jan 13, 2006, at 7:53 PM, gwtmp01@mac.com wrote:

> I understand the desire to generate a sequence of strings
> as defined by the current behavior of String#succ but I don't
> understand
> why you would want to use a Range object as a shortcut to that
> sequence.
> That particular sequence really has nothing to do with an interval
> or the ordering defined by String#<=>

As far as I can tell two classes(Well 4ish) have #succ methods.
Integers and Strings. For all integers x, x has the property that
x.succ > x is true.
There exists at least one String x for which x.succ > x is true, and
at least one String x for which x.succ > x is false. So the question
is, what is a Range? Is it a pair of end-points for checking between-
ness? Is it the set of all values between those end points? If it is
the second, I would argue that #to_a is meaningless for strings
because there are end points for which the set would have infinite
cardinality (i.e. ("a".."b"), the set of strings matched by /^a+\z/
at least is in that "range".).
C06869c119472a139eb163b72040b0db?d=identicon&s=25 Bertram Scharpf (Guest)
on 2006-01-14 02:53
(Received via mailing list)
Hi,

Am Samstag, 14. Jan 2006, 05:49:56 +0900 schrieb James Edward Gray II:
> => false
irb(main):006:0> 2 < 10
=> true
irb(main):007:0> "2" < "10"
=> false

Bertram
C1bcb559f87f356698cfad9f6d630235?d=identicon&s=25 Hal Fulton (Guest)
on 2006-01-14 04:08
(Received via mailing list)
James Edward Gray II wrote:
> => false
In short: Don't do this.

String ranges are very weird. They don't obey the rule that
x.succ > x.

Since "2" > "10", "2" is considered outside the range entirely.

If you really want to do this kind of thing, say
("1".."10").to_a.member?("2")


Hal
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2006-01-14 06:29
Hal Fulton wrote:
> James Edward Gray II wrote:
>> => false
> In short: Don't do this.
>
> String ranges are very weird. They don't obey the rule that
> x.succ > x.
>
> Since "2" > "10", "2" is considered outside the range entirely.
>
> If you really want to do this kind of thing, say
> ("1".."10").to_a.member?("2")
>
>
> Hal

If the two strings have the same length, the weirdness disappears.

Christer
93d566cc26b230c553c197c4cd8ac6e4?d=identicon&s=25 Pit Capitain (Guest)
on 2006-01-14 09:48
(Received via mailing list)
Christer Nilsson schrieb:
> If the two strings have the same length, the weirdness disappears.
Very good point!

Regards,
Pit
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-01-14 12:16
(Received via mailing list)
Hi --

On Sat, 14 Jan 2006, Christer Nilsson wrote:

>> If you really want to do this kind of thing, say
>> ("1".."10").to_a.member?("2")
>>
>>
>> Hal
>
> If the two strings have the same length, the weirdness disappears.

But other weirdnesses arise :-)

irb(main):019:0> ("A".."z").member?("g")
=> true
irb(main):020:0> ("A".."z").to_a.include?("g")
=> false


David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
3a5336a2844502fe58c2c06bc12c32ed?d=identicon&s=25 Stefan Walk (Guest)
on 2006-01-14 15:48
(Received via mailing list)
dblack@wobblini.net wrote:
  > But other weirdnesses arise :-)
>
> irb(main):019:0> ("A".."z").member?("g")
> => true
> irb(main):020:0> ("A".."z").to_a.include?("g")
> => false
>
>
> David
>

IMO, the thing at fault here is that Ranges include Enumerable. From a
mathematical POV, that's nonsense, and that's why oddities like this
exist. Things that can be used for ranges can not used like an
Enumarable (rational..rational, float..float), because those don't have
#succ instance methods... and String ranges behave oddly because the
member? checks use the <=> behaviour, and each uses succ...

Regards,
Stefan
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-01-14 16:39
(Received via mailing list)
On Sat, 14 Jan 2006, Stefan Walk wrote:

> IMO, the thing at fault here is that Ranges include Enumerable. From a
> mathematical POV, that's nonsense, and that's why oddities like this exist.
> Things that can be used for ranges can not used like an Enumarable
> (rational..rational, float..float), because those don't have #succ instance
> methods... and String ranges behave oddly because the member? checks use the
> <=> behaviour, and each uses succ...


but enumerable means neither monotonically increasing nor finite.  so
that a
range includes enumerable means only that one may start, but perhaps
never
finish, to count the elements in the range.  i think this is accurate
isn't
it?

cheers.

-a
3a5336a2844502fe58c2c06bc12c32ed?d=identicon&s=25 Stefan Walk (Guest)
on 2006-01-14 17:07
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
> On Sat, 14 Jan 2006, Stefan Walk wrote:
> but enumerable means neither monotonically increasing nor finite.  so
> that a
> range includes enumerable means only that one may start, but perhaps never
> finish, to count the elements in the range.  i think this is accurate isn't
> it?
>
> cheers.
>
> -a

Enumerable means that you can map the natural numbers to your set in an
invertable way, and that's not possible for ranges of real numbers.
Being enumerable means the possibility of a "succ" operation, and
therefore of traversing the whole set with "each" (which may take
infinite time). Being enumerable implies a working each, now try
(1.0..2.0).each...

Regards,
Stefan
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 18:42
(Received via mailing list)
On Sat, 14 Jan 2006 17:03:59 +0100, Stefan Walk <stefan.walk@gmail.com>
wrote:

>
> Enumerable means that you can map the natural numbers to your set in an
> invertable way, and that's not possible for ranges of real numbers.
> Being enumerable means the possibility of a "succ" operation, and
> therefore of traversing the whole set with "each" (which may take
> infinite time). Being enumerable implies a working each, now try
> (1.0..2.0).each...
>
> Regards,
> Stefan
>


There's nothing wrong with enumerating ranges, you can well have
intervals
of natural numbers or other countably infinite sets. Bounded intervals
of
countable or countably infinite sets are finite sets and may be (not
necessarily though) enumerated in order using the successor operation,
which exists if the elements of the interval are well-ordered. It's not
exactly an edge case, and distinguishing between ranges with finite and
infinite element counts

The issue with strings is that their ordering does _not_ make them such
a
well-ordered countably infinite set. Because strings are compared using
textual comparison, as was already noted in this thread, for every two
given strings, there exists an infinite amount of strings between them.
For the sake of completion, strings in fact _are_ a countably infinite
set, but their ordering doesn't respect any mapping of strings to
natural
numbers.

Given this, the string successor operation doesn't even make sense from
the mathemathical point of view. It is in this context defined ad hoc,
and
it's usefulness lies in contexts of text processing.

Using a string Range is a convenient shortcut, but it's a _hack_.
Nothing
more, nothing less. Strings don't have a solid foundation for use in
maths. If you expect strings to behave as numbers, you're wrong, they're
not supposed to, any bugs are your fault, not the fault of the Ruby core
API. Moan and suffer.

David Vallner
3a5336a2844502fe58c2c06bc12c32ed?d=identicon&s=25 Stefan Walk (Guest)
on 2006-01-14 19:55
(Received via mailing list)
David Vallner wrote:
> There's nothing wrong with enumerating ranges, you can well have
> intervals of natural numbers or other countably infinite sets. Bounded
> intervals of countable or countably infinite sets are finite sets and
> may be (not necessarily though) enumerated in order using the successor
> operation, which exists if the elements of the interval are
> well-ordered. It's not exactly an edge case, and distinguishing between
> ranges with finite and infinite element counts

Your messages seems to have been truncated here. Also, you're wrong,
bounded intervals of countably infinite sets do not have to be finite.
Consider [0,1] in the rational numbers. Rational numbers are countable,
the range is bounded, but the set is not finite (it is still countably
infinite).

> Using a string Range is a convenient shortcut, but it's a _hack_.
> Nothing more, nothing less. Strings don't have a solid foundation for
> use in maths. If you expect strings to behave as numbers, you're wrong,
> they're not supposed to, any bugs are your fault, not the fault of the
> Ruby core API. Moan and suffer.
>
> David Vallner

Range including Enumerable is a fault of the ruby core API, because
(1.0..20) pretends to be enumerable (is_a? returns true, responds_to?
:each returns true), but is not.

Regards, Stefan (who never had problems with string ranges, only with
Range including Enumerable)
8aab717743d4f58a4453adb8b6855e1e?d=identicon&s=25 Robert Retzbach (Guest)
on 2006-01-14 19:58
(Received via mailing list)
James Edward Gray II schrieb:

> => false
>
> James Edward Gray II
>
>
>
I don't know why to_a is working here.
I know that a range from '1' to '10' could be like you described, but it
doesn't make a logical sense I think.
like ('a'..'ah') what should that be?
[a-255.chr] and all a[0.chr-255.chr]?

This is what I think, of course.
Dunno if it makes sense :>

MfG
Retze
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-14 20:19
(Received via mailing list)
On Sat, 14 Jan 2006 19:54:55 +0100, Stefan Walk <stefan.walk@gmail.com>
wrote:

>
> [snip]
>
> Range including Enumerable is a fault of the ruby core API, because
> (1.0..20) pretends to be enumerable (is_a? returns true, responds_to?
> :each returns true), but is not.

That is, of course, misleading, but ranges are very commonly used in the
special cases when they are indeed enumerable, so I can understand why
it's defined that way in the core API. Library design isn't there to
replace programmer brains. You could theorethically check whether the
range endpoints are comparable, and whether the starting one defines
#succ, and then mix in Enumerable to the Ranges that indeed are to get
more strictly correct behaviour.

David Vallner
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-01-14 22:44
(Received via mailing list)
On Sun, 15 Jan 2006, Stefan Walk wrote:

> Enumerable means that you can map the natural numbers to your set in an
> invertable way, and that's not possible for ranges of real numbers. Being
> enumerable means the possibility of a "succ" operation, and therefore of
> traversing the whole set with "each" (which may take infinite time). Being
> enumerable implies a working each, now try (1.0..2.0).each...

that is certainly true.  however, there are no real numbers in computing
-
only rational numbers and rationals are countably infinite

   http://mathworld.wolfram.com/CountablyInfinite.html
   http://mathworld.wolfram.com/RationalNumber.html

while (1.0..2.0).each{|x| p x} cannot work with real numbers it can
certainly
work with a set of rational numbers - in computing terms you can
certainly
count from 1.0 to 2.0 by adding the floating point epsilon.  my opinion
is
that we're talking computer languages here, not mathematicaly ones, and
so any
idea of being 'correct' must be in the context of what computers can do.

in any case, ruby makes no guarantee that

   (a..b).each{|x| p x}

will complete, so even if we had real numbers that would still be a
valid
construct - though mixing in Enumerable into Range would be strange then
- but
it not the case.

cheers.

-a
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-01-14 22:56
(Received via mailing list)
On Jan 14, 2006, at 4:41 PM, ara.t.howard@noaa.gov wrote:

> in any case, ruby makes no guarantee that
>
>   (a..b).each{|x| p x}
>
> will complete, so even if we had real numbers that would still be a
> valid
> construct - though mixing in Enumerable into Range would be strange
> then - but
> it not the case.

Here's a thought, get rid of #each and Enumerable from Range, but add
in a #to_enum method (no args) that would return an Enumerator for
the range. This way programmers could say, "I solemnly swear that I
know  iterating thru a range of strings doesn't make sense with
include, but I want to do it anyway."

("ab".."xyz").to_enum.to_a # etc...

On second thought, that looks unnecessary.

How about:

% cat a.rb
("abc".."wxyz").to_a

% ruby -w a.rb
warning: You fool! By doing this you know include? will make no sense!

Maybe not.

Stupid ranges. Hmph.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-01-14 23:31
(Received via mailing list)
On Sun, 15 Jan 2006, David Vallner wrote:

> You could theorethically check whether the range endpoints are comparable,
> and whether the starting one defines #succ, and then mix in Enumerable to
> the Ranges that indeed are to get more strictly correct behaviour.

but that prevents me from doing this

     harp:~ > cat a.rb
     require "yaml"

     e = Float::EPSILON
     r = 1.0 .. 1.0000000000000091038288019262836314737796783447265625

     class Float
       def succ() self + EPSILON end
     end

     a = r.to_a

     y "r.min" => ("%52.52f" % r.min)
     y "r.max" => ("%52.52f" % r.max)
     y "r.to_a.size" => r.to_a.size



     harp:~ > ruby a.rb
     ---
     r.min: "1.0000000000000000000000000000000000000000000000000000"
     ---
     r.max: "1.0000000000000091038288019262836314737796783447265625"
     ---
     r.to_a.size: 42


i can easily imagine uses for code just like that.  i think it's best if
ruby
will let us run quickly with knives.

regards.

-a
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-01-15 00:13
(Received via mailing list)
On Sat, 14 Jan 2006 23:29:18 +0100, <ara.t.howard@noaa.gov> wrote:

>
> i think it's best if ruby
> will let us run quickly with knives.
>
> regards.
>
> -a


Oh, I agree with that myself. I'm just objecting to the people that
complain when they trip ;P

David Vallner
Ddbfebb47432f6599da361df6a135c7c?d=identicon&s=25 Adam Shelly (Guest)
on 2006-01-16 06:34
(Received via mailing list)
I was messing around with this range behavior after the last discussion,
and
I came up some code that made ranges act, at least to me:
I made range.member?(x0  ==  range.to_a.member?(x) and range.spans?(x)
==
(range.first < x < range.last)  .
I had to implement string.follows? s  which works like the spaceship
operator but uses the string succession rules:

class Range
  def member?(x)
    f=first.follows?(x) and f<0  && l=last.follows?(x) and l>0
  end
  def spans?(x)
    (first<=>x) <=0 && (last<=>x) >=0
  end
end

class Object
  def follows?  other
    self<=>other if self.respond_to? :succ
  end
end

class String
  def is_numeric?
    /^-?\d+$/.match(self)  ? true : false
  end

  def case
    return :upcase if self==self.upcase
    return :downcase if self==self.downcase
    return :mixcase
  end

  def follows? str
    return 0 if str == self
    return 1 if self.is_after? str
    return -1 if str.is_after? self
    return nil
  end

  def is_after? str   #not pretty, but it seems to work...
    #split into groups of letters and digits
    firstparts = str.split(/\W/).map{|c|c.split(/(\d+)/)}.flatten
    lastparts = self.split(/\W/).map{|c|c.split(/(\d+)/)}.flatten
    matching = nil
    return false if lastparts.size != firstparts.size
    if firstparts == [] && lastparts == [] #both strings are all
punctuation
      firstparts = [str]; lastparts = [self]
    end
    #return false on first non-matching or non-following group
    firstparts.each_index do |i|
      next if firstparts[i] == lastparts[i]
      firstparts[i].split_by_case.zip(lastparts[i].split_by_case).each {
|f,l|
        return false if f==nil || l==nil
        next if (matching && l.format_match(f))
        if (f.is_numeric?)
          return false unless l.is_numeric? and l.to_i > f.to_i
        else
          return false if l.case != f.case || l.cmp(f) == -1
        end
        matching = true #this group is in the right order - the rest
just
have to match by format
      }
    end #each
    true
  end

  def split_by_case
    letters = split("").zip(downcase.split(""))
    same = (letters[0][0]!=letters[0][1])
    letters.inject([]){|a,l|
     if (same == (l[0]==l[1]))
        a[-1]+=l[0]
      else
        a<<l[0]
      end
      same = (l[0]==l[1])
      a
    }
  end
  def cmp str
    n = self.length<=>str.length
    return self<=>str if n==0
    n
  end
  def format_match str
    is_numeric? == str.is_numeric? && length == str.length
  end
end

require 'test/unit'
class TestRange < Test::Unit::TestCase
  def test_memberspan
    assert_equal(true, ('a'..'bb').member?('z') )
    assert_equal(false, ('a'..'bb').spans?('z'))
    assert_equal(false,('a'..'bb').member?('aardvark'))
    assert_equal(true,('a'..'bb').spans?('aardvark'))
    assert_equal(true,('a'..'bb').spans?('a'))
    assert_equal(true,('a'..'bb').spans?('bb'))
    assert_equal(false,(1..100).member?(101))
    assert_equal(false,(1..100).spans?(101))
    assert_equal(true,(1..100).member?(11))
    assert_equal(true,(1..100).spans?(11))
    assert_equal(true,(1.5..100).spans?(11))
    assert_equal(nil,(1.5..100).member?(11))
  end
end

-Adam
This topic is locked and can not be replied to.