Is there an easier way to deal with "inout" parameters

  • From: William Adams <william_a_adams@xxxxxxx>
  • To: "luajit@xxxxxxxxxxxxx" <luajit@xxxxxxxxxxxxx>
  • Date: Sun, 19 Aug 2012 15:49:41 +0000

I've literally written a few hundred FFI bindings over the past few months.  
I've come across quite a few patterns, and there's just one that causes some 
amount of pain.

ffi.cdef[[
BOOL getvalue(char *buff, int *len);
]]

This is one of those typical (for Windows at least) functions where you pass in 
a buffer that is to be filled in with some amount of data.  You typically 
allocate the buffer, and pass in the size.  But of course, if the function 
needs a bigger buffer, it will report an error, and tell you what size is 
really needed.  Optionally, you can pass in a buff == NULL, in which case the 
function will tell you what size the buffer should be, by filling in the 'len' 
parameter.  Typical usage:

local needed = ffi.new("int[1]")

local success = C.getvalue(nil, needed)
if not success then
  return nil
end

local buff = ffi.new("uint8_t[?]", needed[0]);
success = C.getvalue(buff, needed);

local value = ffi.string(buff, needed[0]);
print(value);

There are two challenges I have had with this pattern.  The first is just the 
cumbersome nature of having to allocate a buffer to hold the 'needed' value.  
Of course this is required because there is neither an integer data type, nor 
an 'address of' operator.

The second challenge is more insidious.  Although the function requires you to 
pass in the array holding the size of the buffer, it can also alter that value, 
passing back the amount that actually got written.  This might be different 
than what you had allocated, although it is required to be smaller, or the same.

This is where I really miss pointers.

In 'C', this would not be a problem, because in both cases, you just use the 
exact variable:

int len;
getvalue(NULL, &len);
buff = malloc(len);
getvalue(buff, &len);

createstring(buff, len);

Question:  Is there an easier way to conquer this pattern without the error 
prone nature of accessing 'needed[0]'?

Ideally I'd have an 'inout' classifier I could stick onto the parameter.  The 
FFI is already doing magic to marshal data types, so this would be another bit 
of magic.  If I had this, then in Lua I could write:

local len
getvalue(nil, len);
buff = ffi.new("uint8_t[?]", len);
getvalue(buff, len);
ffi.string(buff, len);

That would greatly enhance the quality of FFI wraps, without requiring as much 
typing.  It would eliminate some subtle errors as well.


===============================
- Shaping clay is easier than digging it out of the ground.                     
                  

Other related posts: