Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
new FFI method: attach_method #49
NOTE: I've implemented the changes I thought of as I was submitting the first pull request, and they're at https://github.com/plicease/FFI-Platypus/compare/master...pipcet:attach-object-method?expand=1. That includes documentation and tests, as well as some bug fixes.
it works like attach, but generates an XSUB which will check its first
The tricky part is that the XSUB can be shared between different objects using different libraries and, in future, different "implementations". We cache the last function we've used, so performance should be very good in the typical case, but I haven't tested it. I've learned my lesson about hash lookups in inner loops, so we avoid that.
Now that I've written it, it occurs to me that it might be more useful behavior not to discard the first "object" method, but the specific application I had in mind requires it, and we can always add $ffi->attach_object_method($object, [object_function=>method], ['object'] =>'object') to handle that case.
Note that unlike ->attach, there is no reason we need to lock things into memory permanently: when $object is destroyed, the weak references to it will vanish and the hash entry it refers to will go stale; if necessary, we can even clean up stale hash entries once in a while (I'm not sure whether there is a Perl way of implementing a hash with weak keys, but that's what we'd use).
About the use case: I'm attaching to gdb, which has a function called parse_expression, with a const char * argument and an opaque pointer return value, which I want to call as $gdb->parse_expression($string). Simply using ->attach would pass $gdb as the first argument, which breaks things, and using a wrapper is both slow and limited to a single object, and of course writing a wrapper sub for each method is out of the question.
On second thought, it might be better to define attach_method to work like this:
$ffi->attach_method($object, [function=>'method'] => ['object', 'int'] => 'opaque') makes $object->method(7) call function($object, 7) using $ffi's implementation and its library handles.
$ffi2->attach_method($object, [function=>'method'] => ['void', 'int'] => 'opaque') makes $object->method(7) call function(7) using $ffi2's implementation. (A 'void', in my head, is a type that translates a single Perl argument to zero native arguments on the stack, which is what we want in this case).
$ffi3->attach_method([$object=>$address], [function=>'method'] => ['opaque', 'int'] => 'opaque') makes $object->method(7) call function($address, 7) using $ffi3's implementation.
both of these or multiple variants of either can be combined in the same package.
What do you think? Sorry this got a bit long, but I feel it might be an interesting feature to have. It would be good to decide whether to use the explicit-'void' API or the implicitly discarding API before shipping anything, of course.
I was thinking about implementing an
Don't worry about taking your time, it's not like the patch will go bad. Thanks for looking at it, though if you don't mind I'll prepare a new pull request with my current version sometime this week.
We can also postpone discussing other changes until then. I think I've made a good start on #44 , and some work on performance using @calid's excellent work at https://gist.github.com/calid/17df5bcfb81c83786d6f. I'm quite excited I'll be able to properly benchmark the attach_method code soon.
I apologize for the long lead time to this response!
I've decided to go with #151 to implement method type interfaces. There is a lot that I like about your approach, but I finally decided that implementing class level methods with an "object" type is more flexible and covers more use cases. Now that Platypus supports anonymous code references (like attach but without a name), I think that you can implement most of what you can do with the