Re: Implicit casting issues when binding to C++

  • From: Mike Pall <mike-1207@xxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Mon, 9 Jul 2012 23:42:50 +0200

I wrote:
> However, I might be tempted to include a general, lightweight
> mechanism to override or augment C type conversions. But without
> dragging in half of the C++ implicit type conversion logic into
> the FFI core. I'll need to think about it -- no promises.

Here are some more thoughts on this matter:

First, I don't want to hardcode a conversion matrix or anything
similar. This should be handled by a single metamethod -- in most
cases a couple of type checks should suffice.

One could add a special ctype metamethod (name to be determined)
that's called for a destination type when a conversion would
otherwise fail. This should cover implicit C++ constructors D::D(S).

I'm not too fond of calling an extra metamethod for the source
type, which would cover C++ conversion functions S::operator D()
(but I'll need to do this for real C++ support, of course). This
causes ordering issues, as the first metamethod to be called may
need to signal that it has no matching conversion. [In C++ this is
statically resolved and ambiguities are disallowed.]

In theory, one could simply call the destination ctype to construct
an instance and let the default constructor or __new metamethod
handle everything. However, that might lead to surprises: e.g.
when you accidentally call f(Foo *) with f(1), this would be turned
into f(Foo(1)). This happens to work with many default constructors,
but that's probably not what you want.

IMHO even the existence of __new itself isn't enough to warrant an
implicit constructor call. There's a reason C++ has the (underused)
'explicit' keyword for constructors. If you really want the
implicit conversions and are prepared to handle all possible input
arguments, then you can make the conversion metamethod the same as
__new, of course.

The low-complexity approach is to just call the metamethod from
deep within the C code that does the ctype conversions. Alas, this
creates a non-resumable stack layout, which means one has to force
a trace abort for the JIT-compiler when this happens.

It would require quite a bit of effort to untangle the C code and
make it resumable with some assembler helpers (for every CPU). But
this could be postponed (e.g. to LuaJIT 2.1), since it's upwards-
compatible.

I'm not sure whether a minimal solution (only resolve destination,
not JIT-compiled) would be acceptable or even useful for most users.
Opinions?

--Mike

Other related posts: