Reputation: 5390
Context I want to call a Tcl callback via SWIG from C/C++. More importantly, I want it to be a closure.
Prior knowledge http://computer-programming-forum.com/57-tcl/4481cebe0f09966d.htm (no that wasn't me, just the only thing that seemed similar enough in a Google search)
With Python, I create an object on the Python side, give it a __call__
method, chuck it through SWIG as a PyObject*, and it still has access to non-local variables as coded in Python (with a bit of glue code), because it's still intimately linked with the interpreter it was created in.
My understanding (correct me here) In Tcl, the only way I'm calling a function from C is through a new interpreter by passing a string representing the command (but... then where's the closure...?). If I'm calling C/C++ from Tcl, still have the same problem, because C/C++ doesn't know about the calling Tcl interpreter.
Annnnddd... the documentation (http://www.tcl.tk/man/tcl8.6/TclLib/contents.htm), while extensive, is... well, really extensive. Collective knowledge please save me from my ignorance.
Question How do I get a closure/modify what value a name in Tcl is pointing to from C/C++? Or even just get a handle on an interpreter that's calling into C/C++ code...?
Upvotes: 0
Views: 792
Reputation: 137767
Understand in all this that Tcl's implementation is very much a C library, and so has C ways of doing things, not C++ ones. This might make
What you want is to put the C++ closure as a field in a struct
that you allocate with new
. You then cast the pointer to that struct
as the ClientData
argument to Tcl_CreateCommand
; when the command is invoked, you'll get that pointer back as one of the arguments to the callback function, which you can then cast back to its real type and then invoke. When the command is deleted, you get another callback (if you ask for it) and that is a great time to delete
the allocated struct
. It sounds like a lot of work, but isn't actually.
I don't know exactly how to tie this into a nice SWIGgable approach, as I don't use either SWIG or C++ in my own production code. Maybe put the closure in a normal object and then SWIG that? However, under the covers it is the above that needs to happen. (The type of casts involved are reinterpret_cast<…>
, unfortunately. ClientData
is really just an alias for void *
— unless you're using an ancient version of Tcl with an ancient compiler — along with the promise that the Tcl library code won't poke inside in any way.) I recommend using a struct
because the whole space you've got to hang things off of is just one machine pointer's width in size. What's more, you can probably wrap everything up in a nice class to hide the gory details, but I can't really help you there as I'm no C++ guru.
Upvotes: 0