Re: Relationship between IoTag and IoObject
"dennisf486" <[email protected]>
| Newsgroups | gmane.comp.lang.io |
|---|---|
| Message-ID | <[email protected]> |
> I'm not sure what you mean - you can put whatever you like inside an IoObject's data pointer struct (and an IoCFunction is just another type of IoObject like every other atom in Io).
Right but when you invoke a CFunction on an object, the IoObject *self that you get passed in the callback does not point to the CFunction, it points to the object that is the target of the call, not the CFunction!
(Io pseudocode):
Io> myObj := LikeMagic C++Object clone
==> C++Object_0x1bf49a0
Io> myObj methodA := LikeMagic C++Function clone // pretend this works; I'm using this as pseudocode for binding a IoCFunction
==> CFunction_0x1ce8a60
Io> myObj methodB := LikeMagic C++Function clone // (these methods are actually added using a methodtable on the C API side)
==> CFunction_0x1c45430
// Now suppose both functions above are actually IoCFunction structs that point to this extern "C" function in my LikeMagic project:
IoObject* API_io_userfunc(IoObject *self, IoObject *locals, IoMessage *m)
{
...
}
Here's the problem: "self" in this call points to the object that is the target of the call, LikeMagic C++Object_0x1bf49a0. What points to the CFunction object of the method that was called though? When I'm in API_io_userfunc I do not necessarily know whether methodA or methodB was called. Neither IoObject *self nor IoMessage *m point to CFunction_0x1ce8a60 or CFunction_0x1c45430. The only user-defined data pointer I have (direct) access to is the one in myObj, the target of the call, but that doesn't give me which CFunction got me here or any distinction between whether methodA or methodB was called.
Of course I can do reflection on the IoMessage *m argument to get the message name (and indeed that is what I do) but then I still have to do an additional look up of the message name within a private hashtable structure to get the CallTarget object. And that technique fails if the message name changes, such as if them method is aliased or called via an indirect route.
My main concern though is speed execution speed. It would be much better if the signature of the callbacks were this:
IoObject* API_io_userfunc(IoObject *self, void* user_defined, IoObject *locals, IoMessage *m);
Because then I could just do this:
IoObject* API_io_userfunc(IoObject *self, void* user_defined, IoObject *locals, IoMessage *m)
{
((CallTarget*)user_defined)->invokeOn(IoObject_dataPointer(self));
}
P.S. I looked at the CFFI addon code. It is very interesting. One important difference between how it works and how LikeMagic works is that in CFFI the metadata about function signatures is coded on the Io code side; in LikeMagic the metadata is stored on the C++ side.
P.P.S. Yes, it is very unfortunate that the C/C++ type system doesn't give any clue about ownership of objects, and this does make it difficult to use the bindings. The partial solution to that which I use in LikeMagic is to have two forms of object construction, "new" and "tmp". C++ objects created in Io code with the "new" keyword are passed by pointer and must be deleted when you're done with them. C++ objects created in Io code with the "tmp" keyword are passed generally by value or const& and can be garbage collected. It is still up to the user though to read the documentation of the library he is using to find out whether he is responsible for deleting objects or the library is.