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