On Fri, Jul 26, 2013 at 3:39 PM, Nick Wellnhofer <[email protected]> wrote:
> On Jul 24, 2013, at 12:30 , Nick Wellnhofer <[email protected]> wrote:
>
>> On Jul 24, 2013, at 01:09 , Marvin Humphrey <[email protected]> wrote:
>>
>>> A more robust approach might be to default to generating bindings whenever
>>> possible for every class and every method in a parcel. (C types which
>>> cannot
>>> be mapped automatically, such as `int*`, prevent some methods from being
>>> bound
>>> automatically.) This will cost us in terms of compiled object size and
>>> build
>>> time, but it's conceptually simpler and will cut down on weird edge cases
>>> like
>>> the one we have to disentangle now.
>>
>> I think that's the best solution. We've been generating bindings for most
>> methods anyway.
>
> This is now implemented in branch 'perl-method-bindings'.
Cool! I'm looking forward to deleting a bunch of code from
perl/buildlib/Lucy/Build/Binding/*.pm. :) It would be great if stuff like
this was no longer necessary, because all classes were fully bound by default:
sub bind_andmatcher {
my $binding = Clownfish::CFC::Binding::Perl::Class->new(
parcel => "Lucy",
class_name => "Lucy::Search::ANDMatcher",
);
Clownfish::CFC::Binding::Perl::Class->register($binding);
}
We're close, but not quite there. When I make this change to
perl/buildlib/Lucy/Build/Binding/Search.pm, we lose the autogenerated
constructor binding `XS_Lucy_Search_ANDMatcher_new` from Lucy.xs.
--- a/perl/buildlib/Lucy/Build/Binding/Search.pm
+++ b/perl/buildlib/Lucy/Build/Binding/Search.pm
@@ -21,7 +21,7 @@ $VERSION = eval $VERSION;
sub bind_all {
my $class = shift;
- $class->bind_andmatcher;
+ #$class->bind_andmatcher;
$class->bind_andquery;
> Looking at the code in CFCPerlClass_method_bindings, another question turned
> up. Currently, the Perl bindings generate XSubs for every fresh method to
> support SUPER:: invocations from Perl. But I can't see a legitimate use case
> where this would be needed.
Perhaps there's a misleading comment in the source code, but that's not why we
need to avoid XSUBs like this:
void
serialize(self, outstream)
lucy_Query *self;
lucy_OutStream *outstream;
PPCODE:
Lucy_Query_Serialize(self, outstream); // <--- vtable dispatch
> In my opinion, it only makes sense to invoke a
> method of a superclass on the 'self' object from a subclass. In this case,
> it would be enough to have a single XSub per novel method which uses dynamic
> dispatch.
Consider a `MyQuery` subclass of Query which adds a member variable "num" that
must be serialized.
package MyQuery;
use base qw( Lucy::Search::Query );
sub serialize {
my ($self, $outstream) = @_;
$self->SUPER::serialize($outstream);
$outstream->write_c32($self->get_num);
}
When Clownfish creates the VTable for MyQuery, it will detect that MyQuery has
implemented Serialize() in Perl-space and will install a callback stub
`Lucy_Query_Serialize_OVERRIDE` at `Lucy_Query_Serialize_OFFSET` in the
newly created vtable for MyQuery.
If the XSUB binding for Serialize() were implemented as above, we will wind up
in an infinite loop when we invoke `$my_query->serialize($outstream)`:
1. Enter Perl subroutine `MyQuery::serialize`.
2. Enter XSUB `Lucy::Search::Query::serialize`.
3. Enter callback stub `Lucy_Query_Serialize_OVERRIDE`
4. Goto 1.
To stop the infinite loop, we need to implement the XSUB for
`Lucy::Search::Query::serialize` so that it is fixed to always use the
implementation from Query rather than the implementation extracted from self's
VTable.
void
serialize(self, outstream)
lucy_Query *self;
lucy_OutStream *outstream;
PPCODE:
Lucy_Query_Serialize_t method
= (Lucy_Query_Serialize_t)CFISH_METHOD_PTR(LUCY_QUERY,
Lucy_Query_Serialize);
method(self, outstream);
In order for SUPER invocations to work properly for all methods, we need to
generate one XSUB for each "fresh" method implementation. That's a lot of XS
code, but I don't see a way around it.
Does that make sense?
Marvin Humphrey