in reply to Re^2: OO search in objects
in thread OO search in objects

Subclassing is something programming books teach as immensely important, but is actually pretty damn rare in the real world...

Replies are listed 'Best First'.
Re^4: OO search in objects
by tobyink (Canon) on Aug 15, 2013 at 08:43 UTC

    I've not done any extensive research on the matter, but my impression is that subclassing - in particular, subclassing another author's classes - seems to be done less commonly in Perl than in some other languages, such as Java. (The exceptions being the frequent subclassing of Moose::Object, Mouse::Object and Moo::Object, where the subclassing is not done deliberately, but incidentally by the OO framework in use; and subclassing of Exporter where subclassing is part of its older flawed design, and still used for back-compat with pre-5.57 versions.)

    I mostly put this down to the lack of separation between public, protected and private methods in Perl. In many programming languages, methods are divided into:

    public methods
    The consumer API - i.e. for external code to use.
    protected methods
    The development API - i.e. for subclasses to use.
    private methods
    The internal API - i.e. only used within the class itself.

    In Perl there's the underscore convention, but that confuses several different things. (I'll give Moose examples here, not because Moose is especially bad at this, but because I'm familiar with much of its internals.)

    • Leading underscores get used for esoteric public methods. For example the _inline_check method of Moose::Meta::TypeConstraint gets called by several other module within Moose such as Moose::Meta::Attribute; these are modules which are not subclasses of Moose::Meta::TypeConstraint, so by, say, Java's definition they are public methods even if they're undocumented.

    • Leading underscores get used for methods which are conceptually protected methods. For example, the _process_options method in Moose::Meta::Attribute which is overridden or modified in some way by most of the Moose attribute traits on CPAN, including Moose::Meta::Attribute::Native::Trait which comes with Moose.

    • Leading underscores get used for methods which are conceptually private. For example, _find_next_method_by_name_which_is_not_overridden in Moose::Meta::Class.

    So if I want to write a subclass of something I've found on CPAN, I don't know what methods are safe to override. I don't know which methods are stable to stand on, and which methods might be pulled out from under my feet with the next release.

    If I see an underscore method, is it a part of the public API which the author thought esoteric; is it a method intended for subclasses to override; or is it truly private? I could consult the documentation, but developers rarely document underscore methods. I could consult the source code, but if the method is commented at all, it's probably an explanation of what the method does or how it does it, and not a note about the method's privacy.

    So I forget subclassing, and write a wrapper instead. CPAN is full of wrappers for this and that.

    I think the solution is perhaps a two-level system of documentation, where we encourage developers to document protected methods, and make them as stable as the public methods are between releases. Pod::Weaver-like tools might help, allowing two sets of class documentation (the end-user API docs, and the developer API docs) to be generated from the same input pod.

    Alternatively, adding clear comments to hooks for subclasses in the source code is a good start. I think I've done a fairly good job in MooX::late.

    Getting back to the original question, I'd probably write a MY::FWCollection class, offering add, remove, search, etc methods. I might even make it a subclass of Set::Equivalence. :-)

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name