Adding defaults, changing naming conventions, or collapsing C methods into a single overloaded Lua method can make things look more like Lua, but it's unlikely others will appreciate the difference. It will also cast doubt on other API methods that have been introduced, as the programmer is forced to ask "Will this method behave like the original?"
My rule is that the binding should require almost no added documentation:
* Only documented APIs should be exported.
* Names and capitialization should not be modified unless required (a method name like "end" would be untenable)
* Namespaces should not be modified. For instance, do *not* change glClear to gl.clear or QQuaternion to Qt.Quaternion.
* Parameter lists should not be modified: do not add defaults unless the API supports them. In those cases, still defer to the C API, rather than inlining the default value. The only exception is when an addition would be transparent to the original API.
* Constructible C++ objects and C structs should map to a table with a constructor method named 'new' (or whatever is idiomatic for your binding).
* Multiple return values should be returned to Lua directly
* Extra and reserved arguments should be preserved, not elided. (e.g. void* pointers that are provided for future growth)
* Enum values and constants should not be modified or converted in any unnecessary way.
* API bindings should be as complete as possible. Do not omit unsafe methods or low-level behavior that "no one would ever need." If this must be done, the method should be implemented to throw an error on use.
* A require statement should map to an #include, where possible. This can create a lot of files, but it keeps things orderly.
* Do not introduce extra objects or helpers in your binding. These can introduce confusion until the programmer realizes it's not a binded class, but a personal addition.
A low-level binding should not try to give the same guarantees as Lua in terms of safety. It's tempting to add a bunch of error conditionals, but these are painful to do in practice and not likely to be complete, so just trust the programmer to use it well.
For example, here's a C++ quaternion class that I recently wrote a direct binding for.
require luacxx.QQuaternion
require luacxx.QVector3D
quat:normalize();
print(quat);
There are a few stub methods in this class, but since I adhere strictly to the API, it will be trivial for me or someone else to fill it in using the original documentation once it's needed. This would not be nearly as easy if the binding had my own idioms covering it.
Long story short, if you're writing a binding, I recommend to keep it strict. If the API is ugly or untenable in Lua, then there are bigger issues and a wrapper should be created instead.
--
Aaron Faanes <
dafrito@gmail.com>