Embedding variable numbers of parmeters


(Warden) #1

I’m working on doing some embedding work and I have a function defined
in C, callable in ruby that has a few default parameters. The problem
is that I’m not sure how to tell ruby via the C API that the last
parameters should default to nil or 0 or whatever if they’re not used.

In the mean time I can’t call the “short” version of the function
because it complains about an unmatching number of parmeters. Is there
any way to specify default values from within C?


(Joel VanderWerf) #2

Warden wrote:

I’m working on doing some embedding work and I have a function defined
in C, callable in ruby that has a few default parameters. The problem
is that I’m not sure how to tell ruby via the C API that the last
parameters should default to nil or 0 or whatever if they’re not used.

In the mean time I can’t call the “short” version of the function
because it complains about an unmatching number of parmeters. Is there
any way to specify default values from within C?

Are you using -1 as your argc in rb_define_method? Using -1 asks the
intepreter to pass a variable number of args in a C array.

In that case you can use rb_scan_args to unpack the array, but I don’t
know of any simple way to assign defaults. To avoid doing this manually,
the cgen library (see RAA) gives you a ‘default’ specifier (as well as a
’typecheck’ specifier and an interface to all the functionality of
rb_scan_args). Each default specifier can be a C expression, and it may
refer to previous args.

Here’s an example (taken from examples/sample.rb):

snip…

lib2.define_singleton_method(Point, :test).instance_eval {
c_array_args {
required :arg0, :arg1
optional :arg2, :arg3, :arg4
typecheck :arg2 => Numeric, :arg3 => Numeric
default :arg3 => “INT2NUM(7)”,
:arg4 => "INT2NUM(NUM2INT(arg2) + NUM2INT(arg3))"
rest :rest
block :block
}
body %{
rb_funcall(block, #{declare_symbol :call}, 6,
arg0, arg1, arg2, arg3, arg4, rest);
}

returns nil by default

}

snip…

tester = proc { |arg0, arg1, arg2, arg3, arg4, rest|
argstrs = [arg0, arg1, arg2, arg3, arg4, rest].map { |arg|
arg.inspect
}
printf “test args are: %s, %s, %s, %s, %s, %s\n”, *argstrs
}

Point.test(0, 1, 2, &tester)
Point.test(0, 1, 2, 3, &tester)
Point.test(0, 1, 2, 3, 4, &tester)
Point.test(0, 1, 2, 3, 4, 5, &tester)
Point.test(0, 1, 2, 3, 4, 5, 6, &tester)

output:

test args are: 0, 1, 2, 7, 9, []
test args are: 0, 1, 2, 3, 5, []
test args are: 0, 1, 2, 3, 4, []
test args are: 0, 1, 2, 3, 4, [5]
test args are: 0, 1, 2, 3, 4, [5, 6]