A C++ reference in a Ruby extension

I’m trying to write an extension to access some C++ libraries from
Ruby (1.8.4). One of the C++ functions uses a reference to pass
a value back to the caller as a side effect:

ErrorHandle* DetectInvisibleWatermark(const char *inputfilename,
const char *wmfilename,
float horizOffset,
float vertOffset,
float lowPassFilterFactor,
float &modulationStrength,
const char *key, const char *seed,
const char *outfilename);

(N.B.: “float &modulationStrength”)

Any suggestions on how to handle this reference in an extension?
I don’t have the C++ sources, just libraries and header files.

Thanks,

DGS

On Thu, Apr 12, 2007 at 10:07:52AM +0900, David Simas wrote:

      float lowPassFilterFactor,
             float &modulationStrength,
      const char *key, const char *seed,
      const char *outfilename);

(N.B.: “float &modulationStrength”)
Wrap it in a C function
void foo(float* bar) {
baz(*bar);
}

void baz(float& quux) {
quux /= 1.5;
}

Logan C. wrote:

      float lowPassFilterFactor,

void baz(float& quux) {
quux /= 1.5;
}

There’s still the question of how to get both return values back to the
caller. It depends on how you want to use the function from ruby. You
could return both the ErrorHandle and a float, as a two element array (a
ruby array, that is). The caller can then unpack them like this:

err_h, mod_str = wrap_DetectInvisibleWatermark(…)

Or you could return one and yield the other (a good choice if one is
less likely to be used).

Or maybe return the float (as a ruby float, of course) and rb_raise() if
there is a nonzero ErrorHandle* .

On Thu, Apr 12, 2007 at 10:07:52AM +0900, David Simas wrote:

      float lowPassFilterFactor,
             float &modulationStrength,
      const char *key, const char *seed,
      const char *outfilename);

(N.B.: “float &modulationStrength”)

Any suggestions on how to handle this reference in an extension?
I don’t have the C++ sources, just libraries and header files.

In general, there are two options for handling out parameters:

  1. Treat them as additional return values (so effectively you have
    “return a, b” instead of “return a”) - this is less consistent with
    the C++ interface but is easy to use

  2. Box the value so it can be modified (so for modulationStrength you’d
    pass in Box.new, then get modulationStrength out of the Box) - this
    is more consistent with the C++ interface but IMO is harder to use

But in this case you are using a return value for error handling. I’d
raise an exception instead of returning error values.

As an aside, in general, returning errors in C++ is a bad idea, because
C++ doesn’t provide a good mechanism for returning failure from a
constructor other than an exception. It’s usually better to be
consistent and use exceptions everywhere, rather than only where you
need them.

Paul