Open-ended ranges?

C

Clifford Heath

Folk,

I found Sean Russell's 2001 posting on this subject, and had a play with creating
open ranges using of class instances - interesting to find you can even do this!

What I really want is to be able to define ranges like (1..nil), which is an
open-ended range starting from 1. Of course this doesn't work, but not for the
reason I expected. There seems to be some magic inside MRI that prevents it.

Like if I define:

class End
attr_reader :e
def initialize(e)
@e = e
end
def <=>(other)
@e <=> other.e
end
def succ
@e && @e.succ
end
end

Then I can create the following range: End.new(1) .. End.new(4)
but not this: End.new(1) .. End.new(nil)

Ok, perhaps that's fair enough. But inside class End, replace all
references to @e by @e.to_i (just for the experiment), and it works
(at least, it bitches that 0 is less than 1, but use
End.new(-1) .. End.new(nil)
and it's ok).

Now add puts "#{@e.to_i} <=> #{other.e}"; into the "<=>" method, and
Range "knows" that's not ok... when to my mind it should be ok if the
previous version was.

I haven't taken this any further yet. Until I know that some internal
magic isn't going to stop me making a Range class that works as advertised,
it didn't seem worth pursuing.

What do you think?

Clifford Heath.
 
X

Xavier Noria

What I really want is to be able to define ranges like (1..nil),
which is an
open-ended range starting from 1. Of course this doesn't work, but
not for the
reason I expected. There seems to be some magic inside MRI that
prevents it.

Like if I define:

class End
attr_reader :e
def initialize(e)
@e = e
end
def <=>(other)
@e <=> other.e
end
def succ
@e && @e.succ
end

Note that #succ is expected to return an instance of End. In
particular End.new(nil).succ should return some End instance.

I'd expect as well x < x.succ for all x in End and if you add that
condition you end up putting something at the end of the positive
integers, and adding its successors. As if you put a copy of N after
N. That's one of the examples we talked about some weeks ago:

http://advogato.org/person/fxn/diary/473.html

-- fxn
 
T

Todd Benson

Folk,

I found Sean Russell's 2001 posting on this subject, and had a play with creating
open ranges using of class instances - interesting to find you can even do this!

What I really want is to be able to define ranges like (1..nil), which is an
open-ended range starting from 1.

a = []; a[42]
=>nil

You have, already, tools at your disposal for indefinite ranges of numbers.

Somebody please explain to me what good is a Range object that goes
from 1 to something_undefined? Maybe my SQL background is revealing
itself, but am I being stupid in thinking that this is just plain the
power of flexibility gone awry? I'm seeing a language discontinuity
if people start using this. I get the whole concept of 1 to the
unknown, but unknown to me means I don't even know if it's a Fixnum.

Set.new(1..nil) - Set.new(5..nil)

Is nil supposed to represent infinity? What if we introduce reverse
ranges (i.e. 5..-1). What then does nil represent in a similar line?

Todd
 
T

Todd Benson

irb(main):001:0> 0..(1.0/0)
=> 0..Infinity

HTH,

Right,

(0..(1.0/0)).each { |o| puts "my_range includes " << o.to_s }

It's not indeterminate, it's a definite infinity (within the
computers' capabilities, of course). There's a difference. I suppose
if you use a check within the loop, that might help the use case, but
it still screams of language infidelity.

Of course, I'm just assuming the OP wants 1 to some undetermined
number as an object (a duck) that will quack yes at being asked if
it's a Range.

I'm still trying to figure out why you would want a Range object --
which, by usual definition -- is a _not_ open-ended, have an infinite
side.

Todd
 
T

Todd Benson

(0..(1.0/0)).each { } will never complete though, because 0.succ is
eventually going to be a Bignum, while 1.0/0 is a float value Infinity. Since
a bignum is always going to be less than Infinity, the block is
executed "forever". (Or at least until the bignum runs the machine out of
ram.)

Regards,

Yes, this is something people should understand. Also, having Range
allow an infinite side may very well break existing code. Personally
I have no problem with that, but I think the powers that be should
think it over (or maybe they already have). Ranges, IMHO, have a "set"
type purpose, not a pragmatic one. If people want open-ended ranges,
there's nothing I can really do about it, but I disagree with the
concept whole-heartedly.

I think you and I are mostly in agreement, excepting the fact you may
be more pragmatic than I :)

Todd
 
C

Clifford Heath

Todd Benson wrote:

Firstly Todd, thanks for quoting Konrad, as his messages aren't getting to the newsgroup.
Somebody please explain to me what good is a Range object that goes
from 1 to something_undefined?

I have a meta-language in which it's possible to define value restrictions,
where a value restriction is a list of values or value ranges, including
open-ended ones. I never plan to iterate over an open-ended range (though
I'd expect such a loop to be terminated by exception or some-such), merely
to detect whether a value is allowed by the restriction or not, i.e., either
matches one of the single values or falls inside one of the ranges.

Apart from the open endedness of the ranges in this language (which is not
of my design), the Range object serves perfectly. The Infinity and -Infinity
will serve for numbers, but not for open-ended string ranges.
Set.new(1..nil) - Set.new(5..nil)

Is nil supposed to represent infinity?

No, Infinity will serve for that... but not for Strings. Perhaps the empty
string will serve? It seems to be able to go on either end of a range.
("".."a").each only calls the block once, passing the Range.

Clifford Heath.
 
P

Paul

Todd Benson wrote:

Firstly Todd, thanks for quoting Konrad, as his messages aren't getting to the newsgroup.


I have a meta-language in which it's possible to define value restrictions,
where a value restriction is a list of values or value ranges, including
open-ended ones. I never plan to iterate over an open-ended range (though
I'd expect such a loop to be terminated by exception or some-such), merely
to detect whether a value is allowed by the restriction or not, i.e., either
matches one of the single values or falls inside one of the ranges.

Apart from the open endedness of the ranges in this language (which is not
of my design), the Range object serves perfectly. The Infinity and -Infinity
will serve for numbers, but not for open-ended string ranges.



No, Infinity will serve for that... but not for Strings. Perhaps the empty
string will serve? It seems to be able to go on either end of a range.
("".."a").each only calls the block once, passing the Range.

Clifford Heath.
irb(main):010:0* 1..(1/0.0)
=> 1..Infinity
irb(main):011:0>
irb(main):012:0* (1..(1/0.0)).each { |i| puts i }
1
2
3
4
5
6
etc, etc.
 
X

Xavier Noria

irb(main):001:0> 0..(1.0/0)
=> 0..Infinity

That may work in practice. That is, if that's enough for the purposes
of that Range fine.

Nevertheless, both ends of a Ranges are expected to belong to the same
class, and that class needs a #succ if you are going to iterate over
the Range. In that case, Infinity should have a succ in that example.

Sice it would be desirable (but not required AFAIK) that x < x.succ
for all x, you end up with a copy of N appended after N, (or N**2,
or ...).

-- fxn
 
R

Robert Klemme

2007/11/19 said:
Todd Benson wrote:

Firstly Todd, thanks for quoting Konrad, as his messages aren't getting to the newsgroup.


I have a meta-language in which it's possible to define value restrictions,
where a value restriction is a list of values or value ranges, including
open-ended ones. I never plan to iterate over an open-ended range (though
I'd expect such a loop to be terminated by exception or some-such), merely
to detect whether a value is allowed by the restriction or not, i.e., either
matches one of the single values or falls inside one of the ranges.

Apart from the open endedness of the ranges in this language (which is not
of my design), the Range object serves perfectly. The Infinity and -Infinity
will serve for numbers, but not for open-ended string ranges.


No, Infinity will serve for that... but not for Strings. Perhaps the empty
string will serve? It seems to be able to go on either end of a range.
("".."a").each only calls the block once, passing the Range.

If you are willing to sacrifice the two or three dots then there is
also another solution which nicely integrates with the language:

OpenEnded = Struct.new :start do
include Enumerable

def each
x = self.start
loop do
yield x
x = x.succ
end
self
end
end

for i in OpenEnded.new 10
puts i
break if i > 20
end

Kind regards

robert
 
A

Alex Young

Todd said:
I'm still trying to figure out why you would want a Range object --
which, by usual definition -- is a _not_ open-ended, have an infinite
side.
I can't help but think of lazily evaluated lists here, mainly because
I've got Haskell on the brain at the moment. Infinite lists crop up all
over the place on that side of the fence. The point is that you can
loop over as many elements as you need to, without needing to know how
far down the list you're going to go before you start. Off the top of
my head I can't think of an instance where this approach would be better
than any other in Ruby, or why you might need to pass around a
definition of that list as a discrete object, but I haven't thought very
hard about it :)
 
T

Todd Benson

Dear Clifford,

Defining an open-end class is a great idea; the rang from 1..nil or 0 to nil could help now, I suggest you add different types of parameters to the class such as time.

all the best,

Yes, would it help you really?

Let's make all data define itself. Let's make stuff work for now.
I'm not convinced that 1 to (what's supposed to be) some object of
NilClass will help anybody anywhere.

Todd
 
Y

Yossef Mendelssohn

Yes, would it help you really?

Let's make all data define itself. Let's make stuff work for now.
I'm not convinced that 1 to (what's supposed to be) some object of
NilClass will help anybody anywhere.

This subject has come up more than once. I've worked on it myself, and
found a passable (if incomplete) solution.

What I don't understand is why so many people find an open-ended range
to be pointless. That is to say I do understand why --- because
they're set on iterating over the range --- but I don't understand why
they consider that to be the only use of a range.

Everyone I've seen who's interested in this (myself included) is using
these ranges for another reason, to indicate a range of acceptable (or
maybe even unacceptable values). A range like 5..Infinity is not
intended for iteration, but for comparison.
 
C

Clifford Heath

Robert said:
If you are willing to sacrifice the two or three dots then there is
also another solution which nicely integrates with the language:

Yes, nice, but it's a it more complicated when you have a range with
an open start - it's not clear what "each" should do with (..23).
Probably start at 23 and iterate downwards, I guess.

Clifford Heath.
 
T

Todd Benson

On Nov 19, 6:54 am, "Todd Benson" <[email protected]> wrote:
What I don't understand is why so many people find an open-ended range
to be pointless. That is to say I do understand why --- because
they're set on iterating over the range --- but I don't understand why
they consider that to be the only use of a range.

Well, I suppose for me it is sort of a weird use of the word Range.
Maybe OpenInterval would work better?
Everyone I've seen who's interested in this (myself included) is using
these ranges for another reason, to indicate a range of acceptable (or
maybe even unacceptable values). A range like 5..Infinity is not
intended for iteration, but for comparison.

5..Infinity is not 5..nil. I think it's also not a
5..some_number_to_be_determined_in_the_future. I guess that's the
point I was trying to make. It violates the generic least common
denominator practice present not only in the language, but also its
users.
Sorry if I wasn't clear,
Todd
 
T

Todd Benson

Well, I suppose for me it is sort of a weird use of the word Range.
Maybe OpenInterval would work better?


5..Infinity is not 5..nil. I think it's also not a
5..some_number_to_be_determined_in_the_future. I guess that's the
point I was trying to make. It violates the generic least common
denominator practice present not only in the language, but also its

OK, this last bit sounds a little harsh because I didn't clarify that
the least denominator thing is actually a benefit.

My first post sort of showed how you could use array indices as open
number ranges. Maybe, we could use a class word Interval instead of
OpenInterval or Range? I'll turn to whatever direction works for most
people, but I would like some semblance of a solid interval (i.e. left
and right sides).

Todd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,427
Latest member
HildredDic

Latest Threads

Top