usertypes¶
Perhaps the most powerful feature of sol3, usertypes
are the way sol3 and C++ communicate your classes to the Lua runtime and bind things between both tables and to specific blocks of C++ memory, allowing you to treat Lua userdata and other things like classes.
To learn more about usertypes, visit:
The examples folder also has a number of really great examples for you to see. There are also some notes about guarantees you can find about usertypes, and their associated userdata, below:
- Containers get pushed as special usertypes, but can be disabled if problems arise as detailed here.
- Certain operators are detected and bound automatically for usertypes
- You can use bitfields but it requires some finesse on your part. We have an example to help you get started here, that uses a few tricks.
- All usertypes are runtime extensible in both Lua and C++
- If you need dynamic callbacks or runtime overridable functions, have a
std::function
member variable and get/set it on the usertype object std::function
works as a member variable or in passing as an argument / returning as a value (you can even use it withsol::property
)- You can also create an entirely dynamic object: see the dynamic_object example for more details
- If you need dynamic callbacks or runtime overridable functions, have a
- You can use policies to control dependencies and streamline return values, as well as apply custom behavior to a functions return
- You can work with special wrapper types such as
std::unique_ptr<T>
,std::shared_ptr<T>
, and others by default - Extend them using the sol::unique_usertype<T> traits
- This allows for custom smart pointers, special pointers, custom handles and others to be given certain handling semantics to ensure proper RAII with Lua’s garbage collection
- You can work with special wrapper types such as
- (Advanced) You can override the iteration function for Lua 5.2 and above (LuaJIT does not have the capability) as shown in the pairs example
- (Advanced) Interop with
toLua
,kaguya
,OOLua
,LuaBind
,luwra
, and all other existing libraries by using the stack API’ssol::stack::userdata_checker
andsol::stack::userdata_getter
extension points - Must turn on
SOL_USE_INTEROP
, as defined in the configuration and safety documentation, to use
- Must turn on
- (Advanced) Interop with
Here are some other general advice and tips for understanding and dealing with usertypes:
- Please note that the colon is necessary to “automatically” pass the
this
/self
argument to Lua methods obj:method_name()
is how you call “member” methods in Lua- It is purely syntactic sugar that passes the object name as the first argument to the
method_name
function my_obj:foo(bar, baz)
is the same asmy_obj.foo(my_obj, bar, baz)
- Please note that one uses a colon, and the other uses a dot, and forgetting to do this properly will crash your code
- There are safety defines outlined in the safety page here
- Please note that the colon is necessary to “automatically” pass the
- You can push types classified as userdata before you register a usertype.
- You can register a usertype with the Lua runtime at any time
- You can retrieve a usertype from the Lua runtime at any time
- Methods and properties will be added to the type only after you register the usertype with the Lua runtime
- All methods and properties will appear on all userdata, even if that object was pushed before the usertype (all userdata will be updated)
- Types either copy once or move once into the memory location, if it is a value type. If it is a pointer, we store only the reference
- This means retrieval of class types (not primitive types like strings or integers) by
T&
orT*
allow you to modify the data in Lua directly - Retrieve a plain
T
to get a copy - Return types and passing arguments to
sol::function
-types use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See this note for details
- This means retrieval of class types (not primitive types like strings or integers) by
- You can set
index
andnew_index
freely on any usertype you like to override the default “if a key is missing, find it / set it here” functionality of a specific object of a usertype new_index
andindex
will not be called if you try to manipulate the named usertype table directly. sol3’s will be called to add that function to the usertype’s function/variable lookup tablenew_index
andindex
will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself- If you made a usertype named
test
, this meanst = test()
, witht.hi = 54
will call your function, buttest.hi = function () print ("hi"); end
will instead set the keyhi
to to lookup that function for alltest
types
- You can set
- The first
sizeof( void* )
bytes is always a pointer to the typed C++ memory. What comes after is based on what you’ve pushed into the system according to the memory specification for usertypes. This is compatible with a number of systems other than just sol3, making it easy to interop with select other Lua systems. - Member methods, properties, variables and functions taking
self&
arguments modify data directly - Work on a copy by taking arguments or returning by value.
- Do not use r-value references: they do not mean anything in Lua code.
- Move-only types can only be taken by reference: sol3 cannot know if/when to move a value (except when serializing with perfect forwarding into Lua, but not calling a C++ function from Lua)
- Member methods, properties, variables and functions taking
- The actual metatable associated with the usertype has a long name and is defined to be opaque by the sol implementation.
- The actual metatable inner workings is opaque and defined by the sol implementation, and there are no internal docs because optimizations on the operations are applied based on heuristics we discover from performance testing the system.