Re: opaque pointers and metatype

  • From: Cosmin Apreutesei <cosmin.apreutesei@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Mon, 3 Mar 2014 00:22:29 +0200

> I may, of course, have misunderstood your question. Happens :/

No pb, I'm usually too terse on the first try, it's a bad habit I have.

So there are APIs (like malloc, cairo), where the objects are defined
as opaque structs, and the functions take a pointer to that, and then
there are APIs (like pthreads, fbclient, freetype), where the objects
are defined as pointers to opaque structs, and the functions take a
pointer to that (so the function takes a pointer to a pointer to an
opaque struct). The case I wanted to discuss was the later.

In C, there's not much difference between the two styles, because you
can always take the address of everything with the `&` operator,
regardless of whether that thing is in the stack or heap or whatever.
If it's in RAM, it has an address and you can take it with `&`.

AFAIK, in ffi, there's no addr() function, though I'm not sure why,
because print(ffi.new('double')) does show an address, and I'm pretty
sure that, at least for for structs and arrays, that address is
stable, which is necessary because you can take and hold pointers
pointing inside that struct/array.

So if I have ptr = ffi.cast('void *', some_address), I can't pass &ptr
to a function func(void**) because there's no ffi.addr(ptr). I can
pass ffi.new('void*[1]', ptr) though, but that allocates memory, at
least in some circumstances (someone please correct me if I'm wrong),
plus it's ugly :) As an alternative, I can say that ptr =
ffi.new(void*[1], some_address) and pass ptr around, but then I can't
apply metatype to void*[1].

Yet another alternative is to make a type for void* like this:

   typedef {void *p;} some_type;

and pass that around. And this time around, the ffi is smart enough to
pass some_type by address where some_type* is expected (so it works
with structs but not with scalar cdata). And I can apply metatype on
some_type too, so everything falls into place.

The moral of the story is: in ffi, aggregate types are heap objects
with an address and individual metatable, while scalar types are
values without an address and without a metatable. Sorta like Lua
types. Some double-star C programmers show no respect for this
distinction :) And sometimes I forget it too and think like in C.

I could have got the whole thing wrong of course, happy to be corrected.

Other related posts: