ponder
3.2
C++ reflection library
|
date: 2016-09-18
The biggest change is the decoupling of the runtime usage of the declared data. In CAMP/V1 the declared Function
contains both the data about the function and the call interface. Additionally it contains controls for the calling, i.e. callable()
.
In V2 we are moving towards Function being an immutable data object containing information about the function, but no interface for calling. This has been moved to the "runtime" namespace.
In ponder::runtime
we now have an ObjectCaller
. This retrieves the requested function and allows you to call it. So the use of the Function
data is decoupled from the data. This stops the Function
data from being polluted with a particular usage of the data.
You might notice from the above that several things have been renamed, e.g. arguments are now parameters. In the declaration we declare parameters, i.e. what the function receives. Arguments are what are given to the function when called.
There are also words which have been overloaded, which causes confusion. "Type" can mean a data type, or a group's classification, e.g. int
vs integer. Classifications are now "kinds", i.e. a kind of integer. This might seem pedantic but in an API like this type is used extensively!
enum class ValueKind { None, // No type has been defined yet Boolean, // Boolean type (bool) Integer, // Integer types (unsigned/signed char short int long) Real, // Real types (float, double) String, // String types (char*, ponder::String) Enum, // Enumerated types Array, // Array types (std::vector, std::list, T[]) User // User-defined classes }; enum class FunctionKind { None, // not a function Function, // a function MemberFunction, // function in a class or struct MemberObject, // object in a class or struct FunctionWrapper, // `std::function<>` BindExpression, // `std::bind()` Lambda // lambda function `[](){}` };
Another example is renaming PONDER_RTTI
to PONDER_POLYMORPHIC
(issue #36). The macro only needs to be added to a user API when we want to support polymorphism.
A new feature is the Lua binding generator (issue #40). Please note this is still in development at the current time and could change significantly. This can expose a class declaration to Lua so that the functions can be called and the properties can get and set values. More articles to come.
We can now add non-member functions to a class declaration. This can be a class static function, or a non-class function.
Declared functions that return values can declare return policies. If a function returns, say, a const
reference this is ambiguous. It could either be a reference that will be copied to form a new object, or a reference to an internal object that we want to inspect. We can now use ponder::policy::ReturnCopy
and ponder::policy::ReturnInternalRef
to choose which one to return. The API will bind the function accordingly.
UserObject
s had a parent-child relationship. I am unsure of the use for this and in complicated the UserObject
implementation somewhat so it has been removed.
date: 2016-10-12
In the previous release, Ponder used the runtime metaclass function information at runtime to call functions, i.e. runtime introspection. This can be a little inefficient though as the runtime caller requires us to convert arguments to ponder::Value
s for calling. For example a function accepting a const char*
parameter would generate a temporary std::string
in a ponder::Value
, part of ponder::Args
, which would be discarded after the call. Returns values were also converted to ponder::Value
s, which need to be converted back into user types.
This has been made more efficient, and more flexible, by adding a direct Lua binding. Now the Lua API is used directly from the compile-time metadata, so no ponder::Value
coercion is necessary.
This direct binding also means that the Lua function parameters can be customised, so we can convert user types to Lua types, customised per type if necessary. ponder_ext::LuaValueReader
is used to read Lua values, and ponder_ext::LuaValueWriter
to write back. The ponder_ext
namespace is used here to signify that user extensions are allowed.
Functions can accept Lua table parameters. ponder_ext::LuaTable
can be declared as a function parameter. The binding then expects table to be passed to the declared function and the Lua API can be used to parse the table.
Declare as normal:
From Lua:
p = Parsing() p:init{a=77, b='some text'} -- table is passed to user function assert(p.a == 77 and p.b == 'some text') -- check values set correctly
Declared functions can return multiple values to Lua using tuples. A policy is used to denote this.
Declare:
From Lua:
t = Vec2(11,22) -- create vector x,y = t:get() -- get scalars via multiple return values
The Lua state can be populate with registered enums now.
Declare:
From Lua:
assert(Colour.red == 0) assert(Colour.green == 1) assert(Colour.blue == 2)
In this release we removed the dependency on the fmt print formatter library. Although this is an excellent library it causes problems if a Ponder client application is also using it. See issue #59. We could work around these problems, but fmt was not used extensively so it is easier to remove it and deal with any performance issue directly.