Suppose you really didn’t need the feature that rtleg accepts more than two input arguments. In that case, you can very quickly write a C function to compute the required two argument result:
#include <math.h> extern void crtleg(double *r, double *x, long n); void crtleg(double *r, double *x, long n) { double y; while (n-- > 0) { y = *(x++) / r[0]; *(r++) *= sqrt(1. - y*y); /* result overwrites r input */ } } |
You can now use a PROTOTYPE comment to have codger generate the C wrapper code to make your crtleg function callable from interpreted code. However, you also need to write an interpreted wrapper that will fill in the correct length n, and ensure that the r and x arguments really do have that length, and are conformable arrays. You do all of that in your interface definition file, ‘rtleg.i’, which might look like this:
plug_in, "rtleg"; func rtleg(r, x) { /* convert r to double, broadcast it to result shape */ r = double(r) + array(0.0, dimsof(r, x)); /* broadcast x to result shape, blow up if not conformable */ x += 0.*r; _crtleg, r, x, numberof(r); return r; } extern _crtleg; /* PROTOTYPE void crtleg(double array r, double array x, long n) */ |
When you use this approach, your C source code makes no references at all to yorick. It is both an advantage and a disadvantage that you need to write an interpreted wrapper to handle all of the bookkeeping tasks to ensure that arguments have correct types, shapes, are conformable, and the like. The disadvantage is that you now have to maintain both a compiled and an interpreted piece of code. The advantage is that, as you will see in the next section, the compiled code for consistency and conformability checks is even more tedious than the interpreted code.