Open-ended ranges?

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.

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

···

On Nov 19, 2007, at 1:50 AM, Clifford Heath wrote:

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

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

Fixnum#<=> doesn't like that you're passing nil to it (I think). So you need
to fix your End#<=> definition to only use Fixnum's spaceship operator if the
other end is also a Fixnum. If it's a nilclass, always return whatever would
make the range go on forever :).

Regards,

···

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

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

···

On Nov 18, 2007 6:50 PM, Clifford Heath <no@spam.please.net> wrote:

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.

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

Then again, there is this already:

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

HTH,

···

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

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

···

Clifford Heath <no@spam.please.net> wrote:
  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.

---------------------------------
Never miss a thing. Make Yahoo your homepage.

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

···

On Nov 18, 2007 8:10 PM, Konrad Meyer <konrad@tylerc.org> wrote:

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

HTH,

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

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.

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

···

On Nov 19, 2007, at 3:10 AM, Konrad Meyer wrote:

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

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

···

On Nov 19, 2007 6:44 AM, al_batuul <al_batuul@yahoo.com> wrote:

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,

Quoth Todd Benson:

···

On Nov 18, 2007 8:10 PM, Konrad Meyer <konrad@tylerc.org> wrote:

>
> irb(main):001:0> 0..(1.0/0)
> => 0..Infinity
>
> HTH,
>
> --
> Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

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

(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,
--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

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.

···

On Nov 19, 1:15 pm, Clifford Heath <n...@spam.please.net> wrote:

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.

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

···

2007/11/19, Clifford Heath <no@spam.please.net>:

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.

--
use.inject do |as, often| as.you_can - without end

Todd Benson wrote:

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

···

--
Alex

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.

···

On Nov 19, 6:54 am, "Todd Benson" <caduce...@gmail.com> wrote:

On Nov 19, 2007 6:44 AM, al_batuul <al_bat...@yahoo.com> wrote:

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

--
-yossef

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

Todd

···

On Nov 18, 2007 8:38 PM, Konrad Meyer <konrad@tylerc.org> wrote:

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

Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

One step is needed before the data can define itself is to design a class for training data, to learn about all different data types. Then it is possible for the class to discover and classify its own type by itself.
  I think the number of iterations should be defined within the type algorith and associated to the purpose of the open-ended class,
   
  I would like to see some serious progress in developing this class;
  al_batuul

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

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.

···

Yossef Mendelssohn <ymendel@pobox.com> wrote: On Nov 19, 6:54 am, "Todd Benson" wrote:

On Nov 19, 2007 6:44 AM, al_batuul wrote:

--
-yossef

---------------------------------
Be a better pen pal. Text or chat with friends inside Yahoo! Mail. See how.

Robert Klemme wrote:

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.

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.

--
-yossef

Sorry if I wasn't clear,
Todd

···

On Nov 19, 2007 9:13 AM, Yossef Mendelssohn <ymendel@pobox.com> wrote:

On Nov 19, 6:54 am, "Todd Benson" <caduce...@gmail.com> wrote:

Quoth 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,
> --
>
> Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/
>

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

Todd

I totally agree with you :).

···

On Nov 18, 2007 8:38 PM, Konrad Meyer <konrad@tylerc.org> wrote:

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/