On Thu, Feb 23, 2017 at 9:57 AM, Nick Wellnhofer <wellnho...@aevum.de> wrote:

> CFCPerlClass_method_bindings in CFCPerlClass.c currently generates XSubs for
> overridden methods. The comment states:
>
>     /* Create the binding, add it to the array.
>      *
>      * Also create an XSub binding for each override.  Each of these
>      * directly calls the implementing function, rather than invokes the
>      * method on the object using vtable method dispatch.  Doing things
>      * this way allows SUPER:: invocations from Perl-space to work
>      * properly.
>      */
>
> While this is true, I fail to see a practical use case. IMO, the only place
> where calling a supermethod makes sense is in the method implementation of a
> subclass.

Calling the supermethod from the method implementation of a subclass is
exactly the intended use case.

There's a test in t/binding/019-obj.t to guarantee that it works.

    package SonOfTestObj;
    use base qw( TestObj );
    {
        sub to_string {
            my $self = shift;
            return "STRING: " . $self->SUPER::to_string;
        }
    }

    ...

    $object = SonOfTestObj->new;
    like( $object->to_string, qr/STRING:.*?SonOfTestObj/,
        "overridden XS bindings can be called via SUPER" );

If I make a change like the following in the XS binding, switching from a
hard-coded function to a vtable method invocation...

-    method = CFISH_METHOD_PTR(CFISH_OBJ, CFISH_Obj_To_String);
-    retval = method(arg_self);
+    retval = CFISH_Obj_To_String(arg_self);

... the test will segfault after Perl tells us "Deep recursion on subroutine
"SonOfTestObj::to_string" at t/binding/019-obj.t line 32."

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...

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.

Marvin Humphrey

Reply via email to