> That happens because the method pointer stored in the vtable is a callback > which calls the XSUB which calls the callback which calls the XSUB which calls > the callback…
Thanks again for the explanation. I think this is third time you explained this to me, but I keep forgetting about it. I’ll add a more detailed explanation to the code comment. > PS: While researching this post and preparing an example using SUPER::DESTROY, > I discovered that the implementation for DESTROY is a little wacky right > now. When a Perl subclass implements DESTROY, the method pointer for > Destroy in the subclass vtable doesn't get overridden (possibly because > "destroy" doesn't match "DESTROY" after > https://github.com/apache/lucy-clownfish/commit/64cf00e28a2 ) but stuff > still works because under the Perl bindings cfish_dec_refcount calls > SvREFCNT_dec if there's a cached host object. The commit is what made overriding aliases methods from Perl work. But if you were testing with the latest code from the master branch, I just removed the alias for `Destroy` and added a custom `DESTROY` XSUB to fix the global destruction issue: https://github.com/apache/lucy-clownfish/commit/4aea9977c3 It’s tricky to make overriding custom XSUBs from Perl work. The custom implementation would have to use static dispatch and be implemented for every subclass which overrides the method because of the issue mentioned above. This isn't really needed for Destroy but it might be useful in other cases (also for default interface methods). The key idea is to reuse the XSUB of a novel method for all overridden methods, but without dynamic dispatch. If you have a look at how the ALIAS and INTERFACE keywords work in XS, you’ll see that there’s a slot in CV that can be used to store additional information for XSUBs. We could use it to store a pointer to the subclass: // Single XSUB for a method (novel in MyClass) XS_INTERNAL(XS_MyClass_method) { ... // Get (sub)class with CvXSUBANY. klass = (Class*)CvXSUBANY(cv).any_ptr; // Static dispatch. method = CFISH_METHOD_PTR(klass, MyClass_Method); ... } // Register XSUB for novel methods. CV *cv = newXS(“MyClass::method", XS_MyClass_method, filename); CvXSUBANY(cv).any_ptr = MYCLASS; // Reuse XSUB for overridden method. CV *cv = newXS(“MySubclass::method", XS_MyClass_method, filename); CvXSUBANY(cv).any_ptr = MYSUBCLASS; // Or, for methods from a different parcel. CV *parent_cv = get_cv(“MyClass::method”, 0); CV *cv = newXS(“MySubclass::method", CvXSUB(parent_cv), filename); CvXSUBANY(cv).any_ptr = MYSUBCLASS; Then we’ll only need a way to tell CFC that a there’s a custom XSUB for a method (which can also have an alias) and to suppress the autogenerated XSUB. Custom XSUBs have to use the same static dispatch mechanism, of course. Nick
