Re: ffi type of pointer to

  • From: Mike Pall <mike-1206@xxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Thu, 14 Jun 2012 20:28:33 +0200

Justin Cormack wrote:
> On Tue, Jun 12, 2012 at 3:27 PM, Mike Pall <mike-1206@xxxxxxxxxx> wrote:
> > Well, it's not that difficult to do for the pointer case. But I'd
> > rather go for parameterized types, e.g.
> >
> >  ffi.typeof("$ *", foo_t)
> >  ffi.typeof("struct { $ k; $ v; }[?]", foo_t, bar_t)
> >
> > But I'm not sure whether the complexity is really worth it.
> >
> Not sure about that either - never really needed anything like that in a C
> context.

That's because C is statically typed. C++ added templates to
overcome this limitation (somewhat). We can certainly do better in
Lua. ;-)

Actually, it wasn't that difficult to add parameterized types to
the FFI. The feature is now in git HEAD. No docs, yet, but you can
already play with it:

The '$' character is the marker to be replaced with parameters in
a C type declaration:

* A ctype or a cdata parameter is interpreted like an anonymous
  typedef. You can use that to construct derived types, e.g.
  ffi.typeof("$*", ct) is a pointer to ct, or "$[10]" is a 10
  element array. Unlike simplistic string concatenation, this
  works for all cases (e.g. pointers to function pointers).

* A string parameter is treated like an identifier or keyword,
  except the string is _not_ parsed again or split into words
  (this isn't simple textual substitution). You can use that for
  field names, function names, argument names etc.

  [I'm pondering whether I should drop the keyword and type lookup
  on the string. That would allow you to use arbitrary names for
  fields, even when they collide with keywords or typedefs. I may
  change that before writing the docs.]

* A number parameter is treated as an integer. You can use that
  to construct fixed size arrays. In some contexts you may prefer
  this over VLAs. It works for multi-dimensional types, too. E.g.:

    local matrix_t = ffi.typeof("uint8_t[$][$]", width, height)
    ...
    local m = matrix_t()

Only ffi.typeof() and ffi.cdef() parse parameterized types. The
other functions, e.g. ffi.new(), don't do that, because they
already take other arguments (e.g. initializers). I guess it would
be too confusing to mix two kinds of arguments.

Anyway, parameterized types are a nice tool, but you'll want to
use it sparingly!

The typical scenarios where you'd use templates in C++ come to
mind: e.g. construct a stack or a queue of an arbitrary type.
These need to create an array of the element type, which is now
really easy to do. [Justin's use case]

Another example are derived types of anonymous structs. This
avoids pollution of the struct namespace. [Henk's use case]

I'm sure you'll come up with a lot more use cases.

--Mike

Other related posts: