On Sat, Jun 22, 2013 at 6:20 PM, Nathan Kurz <[email protected]> wrote:
> I wasn't suggesting that Clownfish should backend to Étoilé.  As you
> and Marvin note, much more general than Clownfish needs.  I was
> wondering instead whether its features are superset of what Clownfish
> seeks to provide, to understand whether I should study how it solved
> the fragile ABI problem (which I think it has) or whether its solution
> was inapplicable to Clownfish because it lacked something else
> essential.

Smalltalk-style messaging with or without method caching indeed solves the
fragile ABI problem for dynamic methods.

For speed's sake, though, we accept that all method names must be resolved
statically to specific OFFSET vars.

>> One thing that Objective-C and other dynamic languages support, for
>> example, is adding methods or even instance variables at runtime.
>
> Currently (although underinformed) I think that offering non-fragile
> instance variables is practically synonymous with the ability to
> ability to add instance variables to the compiled extension at
> runtime.  One doesn't need to support this or expose it to the user,
> but behind the scenes I think the implementation will be very similar.

We can add instance variables or methods now through the host.

    package MyObj;
    use base qw( Clownfish::Object );

    my %num;

    sub new {
        my $self = shift->SUPER::new;
        $num{$$self} = 0;
        return $self;
    }

    sub say_hello {
        say "hello";
    }

    sub set_num {
        my ($self, $value) = @_;
        $num{$$self} = $value;
    }

    sub get_num {
        my $self = shift;
        return $num{$$self};
    }

    sub DESTROY {
        my $self = shift;
        delete $num{$$self};
        $self->SUPER::DESTROY;
    }

What we can't do is access those methods or instance variables from C.

    void
    maybe_say_hello (Obj *obj) {
        VTable *vtable = Obj_Get_VTable(obj);
        cfish_method_t say_hello = VTable_Look_Up_Method(vtable, "say_hello");
        if (say_hello) {
            say_hello(obj);
        }
    }

    bool
    maybe_extract_num(Obj *obj, double *num_ptr) {
        VTable *vtable = Obj_Get_VTable(obj);
        return VTable_Extract_Double(vtable, obj, "num", num_ptr);
    }

Potentially, we could add a mechanism to Clownfish for appending additional
instance variables to the ends of objects.  We just have to know about them
when the VTable is first registered so that we can increase the
obj_alloc_size.

Here's how an initialization routine might look which would enable
`maybe_extract_num` above:

    package MyObj;
    use base qw( Clownfish::Object );

    sub INIT_CLASS {
        my $vtable = shift;
        $vtable->add_instance_var(
            type   => 'double',
            name   => 'num',
            setter => 'set_num',    # create Perl-space setter
            getter => 'get_num',    # create Perl-space getter
        );
    }

I dunno.  I can't see how such a thing is really needed, when the only thing
it buys us beyond what we have already is the ability to access unknown
instance vars from C.

Incidentally, I imagine that Glib::Object::Subclass is doing something like
that with its "properties".  It's a pretty complicated interface though.
We've bought ourself an awful lot by caching the host object in the Clownfish
object so that inside-out variables work right.  I don't think inside-out vars
will work with Glib::Object::Subclass because an inner GObject may be
associated with multiple Perl-space objects through the course of its
lifetime:

    
http://search.cpan.org/~xaoc/Glib-1.300/lib/Glib/Object/Subclass.pm#OBJECT_METHODS_AND_FUNCTIONS

    FINALIZE_INSTANCE is called as the GObject is being finalized, that is, as
    it is being really destroyed. This is independent of the more common
    DESTROY on the perl object; in fact, you must NOT override DESTROY (it's
    not useful to you, in any case, as it is being called multiple times!).

I can almost guarantee from that description that the Perl method DESTROY
decrements a reference count on the inner GObject.

> If I squint just right, I can see the start-time registration, object
> configuration, and late-binding as a JIT compile from the dynamic
> "Clownfish" to something efficiently executable.

The distinction I would make between what we're doing and a JIT is that none
of the dynamic capabilities we are implementing require us to create machine
code on the fly.  Also, position-independent code is still fine, we don't need
to patch any call sites and the .text section of the DSO remains shareable
across multiple processes.  But yes, I agree that the line is fuzzy.

Marvin Humphrey

Reply via email to