Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LocalJumpError: no block given #1553

Closed
emboss opened this issue Feb 11, 2012 · 4 comments
Closed

LocalJumpError: no block given #1553

emboss opened this issue Feb 11, 2012 · 4 comments

Comments

@emboss
Copy link

emboss commented Feb 11, 2012

Hi,

I have code where a class can take an arbitrary object responding to each as its value,
and when I call each on the wrapping object, it should actually delegate to the inner object's
each method. Something like this:

o = Object.new
def o.each
yield 1
yield 2
end

val = SomeValue.new(o)
val.each do |e|
puts e
end

I'd expect it to print 1 and 2. The fun part is now that the implementation for delegation happens in C. In the C function for SomeValue#each, I call

rb_iterate(enumerable, rb_each, iter_i, 0);

where iter_i is defined as:

VALUE iter_i(VALUE cur, VALUE arg) { rb_yield(cur); return Qnil; }

In fact, "enumerable" would become what I called o above.
This code works in CRuby 1.9.3, but when I run it on Rubinius master, I get an error message like

Failure/Error: yield 1
LocalJumpError:
no block given

I'm not sure whether this is a bug or whether I'm doing something wrong...
It seems like the block given to val.each is not forwarded to the call on o.each, but I'm not really sure if it is supposed to either.

Thanks in advance,
Martin

@brixen
Copy link
Member

brixen commented Feb 17, 2012

Could you link directly to the code and an actual script that shows the issue?

@emboss
Copy link
Author

emboss commented Feb 18, 2012

Sure, sorry, I should have done that right away.

Given this C code:

#include "localjump.h"

VALUE mLocalJump;
VALUE cLocalJumpTest;

static VALUE
local_jump_init(VALUE self, VALUE value)
{
    rb_iv_set(self, "value", value);
    return self;
}

static VALUE
int_each_i(VALUE cur, VALUE arg)
{
    rb_yield(cur);
    return Qnil;
}

static VALUE
local_jump_each(VALUE self)
{
    VALUE enumerable = rb_iv_get(self, "value");

    if (!rb_block_given_p())
        return rb_funcall(enumerable, 
                       rb_intern("enum_for"), 
                       1, 
                       ID2SYM(rb_intern("each")));

    if (rb_obj_is_kind_of(enumerable, rb_cArray))
        rb_ary_each(enumerable);
    else
        rb_iterate(rb_each, enumerable, int_each_i, Qnil);

    return enumerable;
}

void
Init_localjump(void)
{ 
    mLocalJump = rb_define_module("LocalJump");
    cLocalJumpTest = rb_define_class_under(mLocalJump, "Test", rb_cObject);
    rb_define_method(cLocalJumpTest, "initialize", local_jump_init, 1);
    rb_define_method(cLocalJumpTest, "each", local_jump_each, 0);
}

this Ruby code triggers the error:

o = Object.new
def o.each
  yield 1
  yield 2
  yield 3
end

result=[]
lj = LocalJump::Test.new(o)
lj.each { |i| result << i }
puts [1, 2, 3] == result

The error is triggered in both 1.8 and 1.9 compatibility mode, while it runs and outputs 'true' as expected in CRuby.

@emboss
Copy link
Author

emboss commented Feb 18, 2012

I've also made a mini gem that showcases the behavior. Unfortunately I can't attach it here - please let me know if you're interested and I can publish/send it somewhere.

@emboss
Copy link
Author

emboss commented Feb 24, 2012

Thanks, guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants