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

Add Support for Passing an Array to Proc.Call #100

Open
alecharmon opened this issue Jan 31, 2024 · 1 comment
Open

Add Support for Passing an Array to Proc.Call #100

alecharmon opened this issue Jan 31, 2024 · 1 comment

Comments

@alecharmon
Copy link

I have a scenario where I need to pass an array to a ruby proc. While using magnus proc I noticed that it treats the argument as a RArrayArgList when passing it to proc - this will mean that it gets passed as head, *rest to the ruby proc which is not idea. At the moment I just have a hash wraping it and will do a type check on the arg to the proc. Is there a way to allow arrays as arguments to procs (I tried wrapping in another array but no luck) or is there a better way to wrap the argument to the proc?

@matsadler
Copy link
Owner

I'm unsure of your exact problem as you don't provide an example, but here's a dump of what I know related to your question.

The underlying Ruby API, rb_proc_call, takes its arguments list as a Ruby Array. To make things more convenient to use, rather than have you create a Ruby Array of your arguments yourself, Magnus' Proc::call takes it's arguments list as any type implementing RArrayArgList.

The types that implement RArrayArgList are, Ruby Arrays (so if you happen to already have a Ruby Array of your arguments list, then just pass that), and types that implement ArgList (ArgList is also used for functions that take their arguments list as a C array). The types that implement ArgList are tuples of any type that can be converted to a Ruby type, or a (Rust) array of Ruby types, or a slice of Ruby types.

This means given a calling a proc in Ruby like:

some_proc.call(1,2,3)

You can do the equivalent using Magnus with:

some_proc.call((1,2,3))
// or
some_proc.call([
    ruby.integer_from_i64(1),
    ruby.integer_from_i64(2),
    ruby.integer_from_i64(3),
])?;
// or
let ary = ruby.ary_from_iter([1, 2, 3]);
some_proc.call(ary)

Or given the Ruby:

some_proc.call([1,2,3])

The Magnus equivalent is:

let ary = ruby.ary_from_iter([1, 2, 3]);
some_proc.call((ary,)) // trailing comma denotes a tuple of 1 value
// or
let ary = ruby.ary_from_iter([1, 2, 3]);
some_proc.call([ary])
// or
let ary = ruby.ary_from_iter([1, 2, 3]);
let args = ruby.ary_new_from_values(&[ary]);
some_proc.call(args)

I think the problem you might be running into is that given a proc with arguments like |head, *rest| when calling that proc with a single array argument Ruby will automatically expand the array as if it was an arguments list, e.g. in pure Ruby:

x = proc {|head, *rest| puts "head: #{head.inspect}, rest: #{rest.inspect}"}

x.call(1,2,3)     # prints "head: 1, rest: [2, 3]"
x.call([1,2,3])   # prints "head: 1, rest: [2, 3]"

This is a feature of Ruby that Magnus has no control over.

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

2 participants