Re: Implicit casting issues when binding to C++

  • From: Mike Pall <mike-1207@xxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Tue, 10 Jul 2012 12:48:36 +0200

Janis Britals wrote:
> However there's one more situation requiring "forward" type conversion (i.e.
> based on the source type), and it is static_cast<BaseType*>. This is really
> indispensable for C++.

Well, but that can be done in the conversion metamethod for the
base type (i.e. the destination type) as well, no?

[I know that violates separation of concerns. But I don't want to
hardcode a behavior right now that may need to be reworked for the
'real' C++ support in the future.]

> Luckily it does not need any extra calls into VM,
> just some simple pointer arithmetic. Here maybe the "matrix" solution is not
> such a bad idea after all. You basically need a list of all base ctypes with
> the "offset" you need to add to "this" pointer to get them. Maybe you can
> store them in one tidy table inside ctype metatype (like __base or
> something).

Hardcoding a table lookup in C isn't that much more efficient vs.
doing it in Lua. The internal number of the source type may be
retrieved with tonumber(ffi.typeof(source)) and used as an index.

You can manage such a conversion matrix as part of each base type
and fill it in when creating the derived types.

> In order for me to be able to use 'vanilla' LuaJIT, there is just one small
> additional requirement for this "implicit casting" metamethod: in case it is
> invoked, it would be great if it received the original Lua TValue* as
> argument, or if it is not easily possible, at least preserve the enum
> specification for enum arguments.

The enum type is long gone for the source, since all enums are
converted to numbers when they are retrieved.

And the destination type is always a struct/union type, since
enums don't have metatypes which means no conversion metamethod
could have been invoked.

> Currently enum types are stripped before
> passing to 'lj_cconv_ct_ct' function. Unfortunately C++ enums are not quite
> C enums. In C enum really is synonymous with int, it's just a convenience
> for using constants in code. C++ regards enums as fully separate types, and
> certain method overloads (including implicit constructors) depend on the
> actual enum type of the passed argument.

Well, the problem goes deeper than that. There are many places
where enums are automatically converted from or to numbers or that
need to deal with the corresponding number type and not the enum
type. Not so easy to untangle.

> I even looked at the possibility of
> representing C++ enums in FFI with C structs (using 'struct { int _; }'
> wrapper) in order to preserve their type characteristics, and enable some
> metamethods on them, but in the end decided against it since it introduced
> too much runtime overhead.

That's the first thing I'd have suggested. If you want to preserve
the ctype information, you'll need to box the integer. Whether you
box it in an enum objectg or a struct doesn't really matter. Do
you have an example where this creates too much runtime overhead?

--Mike

Other related posts: