in reply to OO in Perl 5: still inadequate

Why is hashed-based #1 and not #4? What implementation knowledge do I need to subclass a well-written "standard" hash-based Perl class?

Replies are listed 'Best First'.
Re^2: OO in Perl 5: still inadequate
by chromatic (Archbishop) on Jan 21, 2006 at 01:25 UTC

    #1, that it uses blessed hashes. #2, which keys you cannot use for your own purposes in the hash. #3, if it uses accessors.

      I don't understand #3, accessors are what allow ignorance of super classes but you can always look inside a hash accessor and bypass it if you want. #2 I'll deal with in a more general argument in a minute and #1 is included in my "bold claim".

      Here's my bold claim: any class is subclassable without "knowledge" of it's implementation.

      I'll explain the quotes around "knowledge" in a minute.

      All that's required is an inside-out class builder that keys off something like the refaddr of the object and doesn't really care what kind of blessed refs. I'm pretty sure such builders exist, although I can't name one (I can't name any i-o object builder :). If they don't I don't see any great obstacle to building one. Voila - subclassing without knowledge of the superclass's implementation. These classes are themselves subclassable in the same way. All attribute manipulation would be done via accessor methods generated by the builder class, that way encapsulation is advisroy not mandatory.

      So assuming you agree that the above scheme exists or almost exixts, it's time to address "knowledge". Does the above need to know the type of the blessed reference? No. Does it need to know the contents? No. How about the names of any methods? In general, no, however we have to avoid trampling over any undocumented methods in the superclass because they could be called by a method in the superclass and do something completely unexpected.

      These undocumented methods could be a problem but consider the requirement for advisory encapsulation. What this means is that undocumented methods must remain accessible and so it's impossible to avoid this problem. You either want them to be accessble or you don't, you can't have both (this answers #2 above, although for hash based objects, using __PACKAGE__."keyname" for keys also helps a lot).

      So I think it's quite straight forward to achieve both goals for this definition of "knowledge". You cannot{1} avoid having some knowledge if you want to retain advisory encapsulation.

      Example: class Shape uses blessed glob refs. We want to sublcass it for Rectangle which we do, adding 4 undocumented accessors for _Point1, _Point2, Point3, _Point4 and 1 documented Corners. The values for these are stored inside-out and are looked up based on the refaddr of the object. No knowledge of Shape was required apart from that we mustn't add any methods that override Shape's undocumented methods. We can in turn subclass this but we shouldn't override it's undocumented accessors _Point{1-4}.

      Basically if you want advisory encap then can't have total ignorance of the superclass. Given that, the rest is easy.

      {1} Well actually you almost can but it involves wrapping all methods in something that checks the caller to see if the call is coming from inside the superclass in which case we dispatch to the old method, otherwise the new but that's exceedingly ugly and slow and still isn't 100% reliable (think a callback doen from inside the superclass that ends up calling one of these methods, do we give it the inner or outer version?).

        All that's required is an inside-out class builder that keys off something like the refaddr of the object and doesn't really care what kind of blessed refs. I'm pretty sure such builders exist, although I can't name one...

        You can do this with Class::MakeMethods. (Cf. Class::MakeMethods::Template::InsideOut.)

        Not every class is subclassable (although it would be nice if they were), knowledgable or otherwise. Some people do odd things like blessing an object into a hard-coded class (so you don't get to decide which class the object ends up in), have some factory-like behavior going on where the object ends up in a particular class, and lots of other things. Lots of code I see doesn't pass the null-subclass test.

        If you're doing weird wrapper or adapter things, you really aren't subclassing.

        --
        brian d foy <brian@stonehenge.com>
        Subscribe to The Perl Review

        The point was that inside-out objects done using lexical variables are themselves strongly encapsulated. So you can subclass any class without knowing the implementation of the superclass, but your encapsulation is no longer advisory.

        (Well, until xdg made his “err, package vars anyone?” point further down in the thread and I headdesked.)

        Makeshifts last the longest.