diff --git a/docs/bindings.md b/docs/bindings.md index 328b3c28..3fd78614 100644 --- a/docs/bindings.md +++ b/docs/bindings.md @@ -49,6 +49,65 @@ vm->bind(obj, }); ``` +#### How to capture something + +By default, the lambda being bound is a C function pointer, +you cannot capture anything! The following example does not compile. + +```cpp +int x = 1; +vm->bind(obj, "f() -> int", [x](VM* vm, ArgsView args){ + // error: cannot capture 'x' + return py_var(vm, x); +}); +``` + +I do not encourage you to capture something in a lambda being bound +because: +1. Captured lambda runs slower and causes "code-bloat". +2. Captured values are unsafe, especially for `PyObject*` as they could leak by accident. + +However, there are 3 ways to capture something when you really need to. +The most safe and elegant way is to subclass `VM` and add a member variable. + +```cpp +class YourVM : public VM{ +public: + int x; + YourVM() : VM() {} +}; + +int main(){ + YourVM* vm = new YourVM(); + vm->x = 1; + vm->bind(obj, "f() -> int", [](VM* _vm, ArgsView args){ + // do a static_cast and you can get any extra members of YourVM + YourVM* vm = static_cast(_vm); + return py_var(vm, vm->x); + }); + return 0; +} +``` + +The 2nd way is to use `vm->bind`'s last parameter `userdata`, you can store a POD type smaller than 8 bytes. +And use `lambda_get_userdata(args.begin())` to get it inside the lambda body. + +```cpp +int x = 1; +vm->bind(obj, "f() -> int", [](VM* vm, ArgsView args){ + // get the userdata + int x = lambda_get_userdata(args.begin()); + return py_var(vm, x); +}, x); // capture x +``` + +The 3rd way is to change the macro `PK_ENABLE_STD_FUNCTION` in `config.h`: +```cpp +#define PK_ENABLE_STD_FUNCTION 0 // => 1 +``` + +Then you can use standard capture list in lambda. + ### Bind a struct Assume you have a struct `Point` declared as follows.