[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Open-ended ranges?

Clifford Heath

11/19/2007 12:48:00 AM

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

Xavier Noria

11/19/2007 1:23:00 AM

0

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

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

-- fxn


Todd Benson

11/19/2007 1:49:00 AM

0

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.

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

Todd Benson

11/19/2007 2:29:00 AM

0

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

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

Todd Benson

11/19/2007 2:49:00 AM

0

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

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

Clifford Heath

11/19/2007 3:16:00 AM

0

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.

Paul

11/19/2007 6:38:00 AM

0

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

Xavier Noria

11/19/2007 8:32:00 AM

0

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

> 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


Robert Klemme

11/19/2007 8:53:00 AM

0

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.

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

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

Alex Young

11/19/2007 11:31:00 AM

0

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

--
Alex

Clifford Heath

11/20/2007 11:57:00 PM

0

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.