in reply to When to use prototype inheritence?

I should start by admitting to being a co-author and the currenty maintainer of Class::Prototyped, so I'm a bit biased!

My general rule of thumb is that I use C::P when I'm in a situation where someone using the module I'm writing would either need to do one of two things:

This tends to be the generation of what I call behavioral objects (if there is a proper pattern name for this, please let me know:). Examples are objects that interface with database records (all sorts of validation and stuff), objects that interface with individual fields on a database record (even more validation:), etc. Imagine if you had to create a separate class for every field on every table in your database. If you don't do that, though, you're in a world where you pass all these anonymous subroutines as parameters, you've got to write code to implement inheritance yourself, etc., etc. Yeach!

I frequently try to avoid using C::P because I don't want to increase the barrier to usage for modules I'm releasing, but before long I realize that I'm just reinventing the wheel and that there's a reason Ned and I developed C::P! So I bite the bullet, start using it, and suddenly everything starts clearing up.

Now, time for the obligatory sales portion!

C::P is designed to address many of the concerns like those raised by Corion. Quoting from the (rather voluminous) docs:

In Self, everything is an object and there are no classes at all. Perl, for better or worse, has a class system based on packages. We decided that it would be better not to throw out the conventional way of structuring inheritance hierarchies, so in Class::Prototyped, classes are first-class objects.

However, objects are not first-class classes. To understand this dichotomy, we need to understand that there is a difference between the way "classes" and the way "objects" are expected to behave. The central difference is that "classes" are expected to persist whether or not that are any references to them. If you create a class, the class exists whether or not it appears in anyone's @ISA and whether or not there are any objects in it. Once a class is created, it persists until the program terminates.

Objects, on the other hand, should follow the normal behaviors of reference-counted destruction - once the number of references to them drops to zero, they should miraculously disappear - the memory they used needs to be returned to Perl, their DESTROY methods need to be called, and so forth.

What this means is that you should use C::P in such a way that things that are classes get class names. Then people like Corion can easily do things like:

{ my $called; WWW::Mechanize->reflect->addSlot(get => sub { $called++; }); ok( $shell->foo() ); is( $called, 1, '$shell->agent->get was called one time'); }

I think the single greatest insight that Ned and I had was providing a unified OO interface for mucking about with the structure of classes that applies both to C::P created classes and to those written without any knowledge of C::P! The other cool thing about C::P is that because it uses all of the normal Perl class mechanisms (when it creates objects, it creates a new class), you get access to all of the normal Perl behavior, including multiple inheritance. There is no overhead to C::P except for object instantiation (which can be avoided if you want dumb leaf nodes by providing your own new method) and the normal Perl method call overhead. Unless you are using slot attributes, in which case there is the normal Perl subroutine call overhead (different from method overhead in that there is no need to find the implementatation).

Some of the cool features, like slot attributes, are only accessible if you buy into the whole C::P approach, but it's relatively easy to mix and match the C::P approach with more traditional Perl approaches, especially once you grok the few underlying concepts. I will be the first to admit that I've done an incredibly poor job of selling C::P to the community, but part of that is because, independent of time constraints, I don't really know where to start.

OK, enough blathering.

--Toby Ovod-Everett

Replies are listed 'Best First'.
Re: Re: When to use prototype inheritence?
by bsb (Priest) on Sep 16, 2003 at 12:23 UTC
    Thanks very much for your reply.

    Is Class::SelfMethods superceded by C::P then?

    So I bite the bullet, start using it, and suddenly everything starts clearing up.

    I had the same feeling when I started using a really lightweight, prototype-based configuration. All these objects that would've needed either many parameters, tweaking the minute details of their behaviour or a lasagne layers of overrideable methods suddenly became simple, clear and 100% adaptable.

    That experience got me reading about Self, JavaScript and the various Perl modules. I think I'm already sold.

    Brad

    PS. I'll have to read Class::Prototyped, the implementation sounds interesting.
    PPS. You may want to defend C::P over at Class::Classless vs. Class::Prototyped