On 26/06/2015 04:06, Marvin Humphrey wrote:
Consider a method with an interface type argument
Obj*
Fetch(Hash *hash, Hashable *key);
That should be `Hashable key` rather than `Hashable *key` -- right?
Right.
Does this approach make sense?
https://github.com/rectang/lucy-clownfish/commits/iface_exp1
Obviously some of that code would be autogenerated by CFC.
I think it would work for Perl, Python, Ruby, etc -- languages which
resolve method names on each invocation.
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.
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;
}
* 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.
Nick