On Fri, Jun 26, 2015 at 7:41 AM, Nick Wellnhofer <[email protected]> wrote:
> The question is how to deal with wrapped Clownfish objects that are passed
> as interface type arguments.  For example, the `key_sv` passed to
> Stringify_And_Fetch might be a Clownfish::Obj. In this case, it should work
> to wrap it a second time as HostStringable. But this would make interface
> method calls a lot slower. Calling Stringify on such a doubly wrapped object
> would go through S_call_stringify, call_method, and the generated XS
> wrapper, instead of invoking Stringify directly.

Indeed.

> So if a Clownfish::Obj is passed as interface type argument, we should check
> whether it implements the interface and create an interface object with the
> itable of the Obj's class, not the host object itable. Something like:
>
>     Stringable_t
>     sv_to_stringable(SV *sv) {
>         Obj *obj;
>         ITable *itable;
>
>         if (sv_derived_from(sv, "Clownfish::Obj")) {
>             IV iv_ptr = SvIV(SvRV(sv));
>             obj = INT2PTR(cfish_Obj*, iv_ptr);
>             itable = Obj_lookup_itable(obj, STRINGABLE);
>             if (itable == NULL) {
>                 THROW(ERR, "%o doesn't implement Stringable",
>                       Obj_get_class_name(obj));
>             }
>             INCREF(obj);
>         }
>         else {
>             // Pure Perl object.
>             obj = HostStringable_new(sv);
>             itable = XSBind_hoststringable_itable();
>         }
>
>         Stringable_t stringable = { obj, itable };
>         return stringable;
>     }

I can't think of anything better than a hash table lookup.  We can probably
reuse LockFreeRegistry for this purpose.

>> *   Allocate the wrapper object on the stack, similar to our approach with
>>      stack-allocated String.
>
> This only works if we made the host objects "clone on incref" like stack
> Strings.

Is there any reason not to?  The use case seems even more apt than strings.

Here's how I'd tweak that conversion function... pass in stack-allocated
memory for use as a HostObj if necessary, avoid the INCREF:

    Stringable_t
    sv_to_stringable(SV *sv, void *allocation) {
        Obj *obj
        ITable *itable;

        if (sv_derived_from(sv, "Clownfish::Obj")) {
            IV iv_ptr = SvIV(SvRV(sv));
            obj = INT2PTR(cfish_Obj*, iv_ptr);
            itable = Obj_lookup_itable(obj, STRINGABLE);
            if (itable == NULL) {
                THROW(ERR, "%o doesn't implement Stringable",
                      Obj_get_class_name(obj));
            }
        }
        else {
            // Pure Perl object.
            obj = CLASS_INIT_OBJ(HOSTOBJ, allocation);
            ((HostObj*)obj)->host_obj = sv;
            itable = XSBind_hoststringable_itable();
        }

        Stringable_t stringable = { obj, itable };
        return stringable;
    }

Marvin Humphrey

Reply via email to