I consider this a bug in Ruby

I would like to know why the following code doesn’t work:

This should be 1 followed by 13 zeroes…

range = 0…10000000000000

This should be 1 followed by 12 zeroes…

range.step(1000000000000){|i| puts i}

The error I get is this:

RangeError: bignum too big to convert into ‘long’

Why is there any "converting" to do?  How can this not work?
My best guess is that the Range class is not written in Ruby and, 

hence,
has funny limitation on how it may work. If this is the case, it is
totally
unnecessary. One of the things I like about Ruby is how much of Ruby
can be
written in Ruby. “require” can be written in Ruby, “attr_accessor” can
be
written in Ruby and Range can be written in ruby.
What’s going on, here?
Thank you…

Hi,

At Wed, 5 Dec 2007 08:40:11 +0900,
Just Another Victim of the Ambient M. wrote in [ruby-talk:282100]:

Why is there any "converting" to do?  How can this not work?
My best guess is that the Range class is not written in Ruby and, hence, 

has funny limitation on how it may work.

Yes, and performance issue.

Index: stable/range.c

— stable/range.c (revision 14103)
+++ stable/range.c (working copy)
@@ -255,10 +255,18 @@ range_each_func(range, func, v, e, arg)

static VALUE
-step_i(i, iter)
+step_i(i, arg)
VALUE i;

  • long *iter;
  • VALUE arg;
    {
  • iter[0]–;
  • if (iter[0] == 0) {
  • VALUE *iter = (VALUE *)arg;
  • if (FIXNUM_P(iter[0])) {
  • iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
  • }
  • else {
  • VALUE one = INT2FIX(1);
  • iter[0] = rb_funcall(iter[0], ‘-’, 1, &one);
  • }
  • if (iter[0] == INT2FIX(0)) {
    rb_yield(i);
    iter[0] = iter[1];
    @@ -308,11 +316,20 @@ range_step(argc, argv, range)
    if (rb_scan_args(argc, argv, “01”, &step) == 0) {
    step = INT2FIX(1);
  • unit = 1;
  • }
  • else if (FIXNUM_P(step)) {
  • unit = NUM2LONG(step);
  • }
  • else {
  • VALUE tmp = rb_to_int(step);
  • unit = rb_cmpint(tmp, step, INT2FIX(0));
  • step = tmp;
    }
  • unit = NUM2LONG(step);
    if (unit < 0) {
    rb_raise(rb_eArgError, “step can’t be negative”);
  • }
  • if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
  • }
  • if (unit == 0)
  • rb_raise(rb_eArgError, “step can’t be 0”);
  • if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are
    special */
    long end = FIX2LONG(e);
    long i;
    @@ -331,11 +348,9 @@ range_step(argc, argv, range)

if (!NIL_P(tmp)) {

  •  VALUE args[5];
    
  •  long iter[2];
    
  •  VALUE args[5], iter[2];
    
     b = tmp;
    
  •  if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
     args[0] = b; args[1] = e; args[2] = range;
    
  •  iter[0] = 1; iter[1] = unit;
    
  •  iter[0] = INT2FIX(1); iter[1] = step;
     rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i,
     (VALUE)iter);
    

@@ -344,5 +359,4 @@ range_step(argc, argv, range)
ID c = rb_intern(EXCL(range) ? “<” : “<=”);

  •  if (rb_equal(step, INT2FIX(0))) rb_raise(rb_eArgError, "step 
    

can’t be 0");
while (RTEST(rb_funcall(b, c, 1, e))) {
rb_yield(b);
@@ -351,7 +365,6 @@ range_step(argc, argv, range)
}
else {

  •  long args[2];
    
  •  VALUE args[2];
    
  •  if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
     if (!rb_respond_to(b, id_succ)) {
    

    rb_raise(rb_eTypeError, “can’t iterate from %s”,
    @@ -359,6 +372,6 @@ range_step(argc, argv, range)
    }

  •  args[0] = 1;
    
  •  args[1] = unit;
    
  •  args[0] = INT2FIX(1);
    
  •  args[1] = step;
     range_each_func(range, step_i, b, e, args);
    
    }
    Index: trunk/range.c
    ===================================================================
    — trunk/range.c (revision 14103)
    +++ trunk/range.c (working copy)
    @@ -248,8 +248,14 @@ static VALUE
    step_i(VALUE i, void *arg)
    {
  • long *iter = (long *)arg;
  • VALUE *iter = arg;
  • iter[0]–;
  • if (iter[0] == 0) {
  • if (FIXNUM_P(iter[0])) {
  • iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
  • }
  • else {
  • VALUE one = INT2FIX(1);
  • iter[0] = rb_funcall(iter[0], ‘-’, 1, &one);
  • }
  • if (iter[0] == INT2FIX(0)) {
    rb_yield(i);
    iter[0] = iter[1];
    @@ -298,13 +304,20 @@ range_step(int argc, VALUE *argv, VALUE
    if (rb_scan_args(argc, argv, “01”, &step) == 0) {
    step = INT2FIX(1);
  • unit = 1;
  • }
  • else if (FIXNUM_P(step)) {
  • unit = NUM2LONG(step);
  • }
  • else {
  • VALUE tmp = rb_to_int(step);
  • unit = rb_cmpint(tmp, step, INT2FIX(0));
  • step = tmp;
    }
  • unit = NUM2LONG(step);
    if (unit < 0) {
    rb_raise(rb_eArgError, “step can’t be negative”);
  • }
  • }
    if (unit == 0)
    rb_raise(rb_eArgError, “step can’t be 0”);
  • if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
  • if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are
    special */
    long end = FIX2LONG(e);
    long i;
    @@ -323,12 +336,11 @@ range_step(int argc, VALUE *argv, VALUE

if (!NIL_P(tmp)) {

  •  VALUE args[2];
    
  •  long iter[2];
    
  •  VALUE args[2], iter[2];
    
     b = tmp;
     args[0] = e;
     args[1] = EXCL(range) ? Qtrue : Qfalse;
    
  •  iter[0] = 1;
    
  •  iter[1] = unit;
    
  •  iter[0] = INT2FIX(1);
    
  •  iter[1] = step;
     rb_block_call(b, rb_intern("upto"), 2, args, step_i, 
    

(VALUE)iter);
}
@@ -344,5 +356,5 @@ range_step(int argc, VALUE *argv, VALUE
}
else {

  •  long args[2];
    
  •  VALUE args[2];
    
     if (!rb_respond_to(b, id_succ)) {
    

@@ -350,6 +362,6 @@ range_step(int argc, VALUE *argv, VALUE
rb_obj_classname(b));
}

  •  args[0] = 1;
    
  •  args[1] = unit;
    
  •  args[0] = INT2FIX(1);
    
  •  args[1] = step;
     range_each_func(range, step_i, b, e, args);
    
    }
    @@ -867,6 +879,4 @@ void
    Init_Range(void)
    {
  • VALUE members;
  • id_cmp = rb_intern("<=>");
    id_succ = rb_intern(“succ”);

On Dec 5, 2007 7:40 AM, Just Another Victim of the Ambient M.
[email protected] wrote:

RangeError: bignum too big to convert into ‘long’

possible bug. bignum is really too big for long :slight_smile:

Why is there any "converting" to do?  How can this not work?

range is expensive.
try numeric step,

irb(main):010:0> r=1_000_000_000_000
=> 1000000000000
irb(main):011:0> r.step(r*10,r){|x| p x}
1000000000000
2000000000000
3000000000000
4000000000000
5000000000000
6000000000000
7000000000000
8000000000000
9000000000000
10000000000000
=> 1000000000000
irb(main):012:0>

kind regards -botp

“Nobuyoshi N.” [email protected] wrote in message
news:[email protected]

Hi,

At Wed, 5 Dec 2007 08:40:11 +0900,
Just Another Victim of the Ambient M. wrote in [ruby-talk:282100]:

Why is there any "converting" to do?  How can this not work?
My best guess is that the Range class is not written in Ruby and, 

hence,
has funny limitation on how it may work.

Yes, and performance issue.

Just so I'm clear on this; the Range class is implemented in C for

performance reasons? Was the performance of a Ruby version actually an
issue? I don’t think anybody here uses Ruby for its blazing speed.
I’ve
said this before but I guess it bears repeating. I don’t use Ruby to
write
fast programs, I use Ruby to write programs fast. This is, obviously,
just
a personal opinion but that’s the role Ruby plays for me and I think
it’s
the most common case.
Furthermore, I think there is an important lesson to be had, here.
There are many different stories, out there, that exemplify this but
they
all end with the same phrase: I can make my program fast, too, if it
didn’t
have to work. This implementation of Range doesn’t work. At the very
least, it’s buggy, which, to some people, is the same thing.
Even if performance were important, it didn’t even fall back onto a
Ruby
implementation. It might be a little harder to maintain but you could
write
a Ruby version and use that whenever you encounter a “RangerError:
bignum
too big to convert into ‘long’” error. I don’t think Range changes too
much
between Ruby releases, so I really don’t see it being a maintenance
headache. Again, generally, speaking, a slow program that works is
better
than a fast program that doesn’t work…
Finally, the .each method worked! I didn’t let it run all the way
to
MAX_LONG, or whatever the constant is, if there is a constant, but you
all
know what I mean. Maybe a bug occurs there but what little I let run
worked. How can .each work but .step not work? Especially ironic since
.step produced less iterations than .each. I mean, where’s the concern
for
performance, there? You’d imagine that there’d be more concern for
performance for .each since it will produce more iterations…
So, perhaps all this can be fixed for Ruby 1.9 and Rite? What do
you
all think?
Thank you…

“botp” [email protected] wrote in message
news:[email protected]

8000000000000
9000000000000
10000000000000
=> 1000000000000
irb(main):012:0>

In what way is Range expensive?  Why is it so expensive?
Thank you...

Hi,

At Wed, 5 Dec 2007 14:25:07 +0900,
Just Another Victim of the Ambient M. wrote in [ruby-talk:282132]:

Yes, and performance issue.

Just so I'm clear on this; the Range class is implemented in C for 

performance reasons?

It isn’t the only reason why Range is implemented in C, I wrote
about your “limitation.”

If Range were written in Ruby, it couldn’t be used until
something was loaded. It wasn’t acceptable for intrinsic
classes.

Just Another Victim of the Ambient M. wrote:

Just so I'm clear on this; the Range class is implemented in C for 

performance reasons? Was the performance of a Ruby version actually an
issue? I don’t think anybody here uses Ruby for its blazing speed.

Perhaps not yet, or not 1.8.6. But this is going to change.

  • Charlie

Just Another Victim…:

I would like to know why the following code doesn’t work:

This should be 1 followed by 13 zeroes…

range = 0…10000000000000

This should be 1 followed by 12 zeroes…

range.step(1000000000000){|i| puts i}

fyi, to help with counting zeros, you can use an underscore like a
comma:

range = 0…10_000_000_000_000

On Dec 5, 7:40 am, “Just Another Victim of the Ambient M.”
[email protected] wrote:

“Nobuyoshi N.” [email protected] wrote in message

If Range were written in Ruby, it couldn’t be used until
something was loaded. It wasn’t acceptable for intrinsic
classes.

Okay, this makes more sense to me.  So, some built-in classes use Range

and they couldn’t if it were written in Ruby.
This brings up several issues. One would be, why not? Wouldn’t it be
nice if the Ruby interpreter’s built in classes could be written in Ruby?

Well, might be nice for people who want to hack on very low-level ruby
stuff without going into the C, but not a good idea. PyPy (a python
interpreter written in python) is a factor of 2000 times slower(!)
than cPython when running on top of cPython. Implementing the base
classes of ruby in ruby, would have similar negative performance
impact.

Now, I understand that implementation issues can be hard to solve but it’s
certainly something to keep in mind for something like Ruby 1.9 or Rite…
Another issue would be: did they have to use a long? Just 'cause the
implementation of Range is written in C doesn’t mean that they couldn’t
still use Bignum, does it? More to the point, couldn’t the Ruby C code be
written so that it didn’t care what type was passed in, as long as they
supported integral operations? I’d be surprised if it couldn’t…
Thank you…

Looks like Nobu posted the patches above.

Regards,
Jordan

Hi,

In message “Re: I consider this a bug in Ruby…”
on Wed, 5 Dec 2007 11:09:10 +0900, Nobuyoshi N.
[email protected] writes:

|> Why is there any “converting” to do? How can this not work?
|> My best guess is that the Range class is not written in Ruby and, hence,
|> has funny limitation on how it may work.
|
|Yes, and performance issue.

Commit the patch, please.

          matz.

“Nobuyoshi N.” [email protected] wrote in message
news:[email protected]

[ruby-talk:282100]:
It isn’t the only reason why Range is implemented in C, I wrote
about your “limitation.”

Where did you write about this?  I'd be happy to read it...

If Range were written in Ruby, it couldn’t be used until
something was loaded. It wasn’t acceptable for intrinsic
classes.

Okay, this makes more sense to me.  So, some built-in classes use 

Range
and they couldn’t if it were written in Ruby.
This brings up several issues. One would be, why not? Wouldn’t it
be
nice if the Ruby interpreter’s built in classes could be written in
Ruby?
Now, I understand that implementation issues can be hard to solve but
it’s
certainly something to keep in mind for something like Ruby 1.9 or
Rite…
Another issue would be: did they have to use a long? Just 'cause
the
implementation of Range is written in C doesn’t mean that they couldn’t
still use Bignum, does it? More to the point, couldn’t the Ruby C code
be
written so that it didn’t care what type was passed in, as long as they
supported integral operations? I’d be surprised if it couldn’t…
Thank you…

On Dec 5, 2007 7:46 AM, Just Another Victim of the Ambient M.
[email protected] wrote:

Just so I'm clear on this; the Range class is implemented in C for

classes.

Okay, this makes more sense to me.  So, some built-in classes use Range

and they couldn’t if it were written in Ruby.
This brings up several issues. One would be, why not? Wouldn’t it be
nice if the Ruby interpreter’s built in classes could be written in Ruby?

That’s what Rubinius is.

http://rubini.us/

Now, I understand that implementation issues can be hard to solve but it’s
certainly something to keep in mind for something like Ruby 1.9 or Rite…
Another issue would be: did they have to use a long? Just 'cause the
implementation of Range is written in C doesn’t mean that they couldn’t
still use Bignum, does it? More to the point, couldn’t the Ruby C code be
written so that it didn’t care what type was passed in, as long as they
supported integral operations? I’d be surprised if it couldn’t…
Thank you…

That’s what Nobuyoshi’s patch is about.

“Gerardo S. Gómez Garrido” [email protected] wrote in
message
news:[email protected]

“Nobuyoshi N.” [email protected] wrote in message

has funny limitation on how it may work.

nice if the Ruby interpreter’s built in classes could be written in Ruby?

That’s what Rubinius is.

http://rubini.us/

Rubinius is a virtual machine implementation.  I'm not sure how this

relates…

Thank you...

That’s what Nobuyoshi’s patch is about.

Oh, so the code that Nobuyoshi posted was a patch that fixed this

problem? MonkeeSage also mentioned that and it would explain
Nobuyoshi’s
comment about “wrote about your limitation.” I didn’t understand the
code
and he posted it with no context (no summary on what the code was or why
he
posted it).
In that case, excellent! I’m glad to see Ruby’s implementation
improving…

On Dec 5, 2007 10:40 AM, Just Another Victim of the Ambient M.
[email protected] wrote:

Why is there any "converting" to do?  How can this not work?

It isn’t the only reason why Range is implemented in C, I wrote
Range
relates…
From the web page I linked to:

“Rubinius implements the core libraries in Ruby, providing a system
that is much more accessible, easier to develop and to extend.”