"...JRuby does not have an equivalent for rb_scan_args(), or at least not one that is called on a per-method basis."
In the comments, Ola Bini -- ThoughtWorker and JRuby committer -- graciously pointed out that there are, in fact, two static methods that we can use to simulate the function of
rb_scan_args(), both found in the
checkArgumentCount()does just what it says. You pass it an array of argument values, along with the minimum and maximum number of all arguments, and it verifies that the actual number of arguments falls within that range (inclusive). So this provides some basic sanity checking of the number of arguments passed to the method you're implementing. If the number of arguments is valid,
checkArgumentCount()returns the actual number of arguments passed. I guess you could argue that this isn't very useful, since you already know the number of arguments you expect, as well as the number given to you. But it is used in a number of places in the JRuby source code.
scanArgs()will do a little more work for you. It will do the same sanity checking (it actually calls
checkArgumentCount()to do so), although you specify the numbers slightly differently, passing the number of required arguments along with the number of optional arguments. If the actual number of arguments passed is valid,
scanArgs()then creates a new array of length required + optional, copies the values of any arguments passed in (all required arguments plus any provided optional arguments), sets the values of any non-provided optional arguments to nil, and returns the new array. This actually is useful, as it transforms a variable-length array of arguments into one of fixed length, where the fixed length is always equal to the maximum number of arguments your method will accept.
As Ola points out, this still is not quite the equivalent of MRI
rb_scan_args(), in that it doesn't handle "rest" or "block" arguments. But it does offload from us some of the burden of handling variable length argument lists.
I do plan to use
scanArgs()to finish up my implementation of
BigDecimal.mode(), but in order to so meaningfully I'm also going to have to change
mode()'s method definition from taking a fixed number of arguments to taking a variable number of arguments (the first argument is required, the second is optional). That's going to involve digging into JRuby's mechanism for defining Ruby methods, which I've researched and found to be pretty cool, but it's going to take another few blog posts to sort out. Stay tuned...