in reply to Beyond Inside-Out

I would like to check that I have understood your technique properly. Do I have this correct?

The purpose of this module is to:

You do this by:

The obvious benefits are:

  • The properties belonging to a particular class cannot interfere with the properties from a super/sub-class
  • It doesn't matter what type the original object is - any object can be subclassed
  • It is fast and not convoluted
  • It catches run-time typos when trying to access properties (except in the methods which live in the class itself)
  • Questions

    I hope I've understood this correctly - and corrections appreciated

    thanks,

    clint

    Replies are listed 'Best First'.
    Re^2: Beyond Inside-Out
    by Anno (Deacon) on May 30, 2007 at 11:33 UTC
      The purpose of this module (Alter) is to:

    • Allow arbitrary subclassing of any object without interfering with its super or subclasses

      Yes.

    • Only allow access to properties via methods, instead of accessing them directly via (eg) hash keys

      No. Unlike inside-out, Alter doesn't organize object data in hashes keyed by id. Each class sees the object as a single reference (type of its choice). It's up to the class to organize the data further.

    • Automate garbage collection

      Yes. And thread-cloning.

      The mechanism is actually even simpler than your sketch.

      Assume there is a function of a single variable _corona($obj). For each object it produces a single hash(ref) that is autovivified empty on the first call, and stays with the object for its lifetime. This function is not caller-sensitive. The caller-dependent behavior of Alter::ego() can then be described in Perl (code untested):

      package Alter; sub ego { my $obj = shift; my $corona = _corona($obj); my $class = caller; return $corona->{ $class} if exists $corona{$class} ); $corona{ $class} = shift || {}; }
      Thus the mechanism is: Equip each object (magically) with one hidden hash, its corona. Use that hash, keying by class name, to store the individual alter ego of the object for each class.

      The technique does nothing to catch misspelled attribute names, it doesn't know of attributes. It brings back the (good or bad, but old) days when "an object is nothing but a reference", only this time an individual one for every class.

      To your questions, skipping the one about Tye's concern.

    • I don't understand why garbage collection works...

      Garbage collection and thread cloning are magic-aware, that's "all" there's to it (which is a lot). That makes magic a good choice for object data. It's out of band to normal Perl code (like the id-keyed hashes of inside-out), but Perl knows about magic and deals with it.

    • You mention of problem of serialization. Your solution doesn't help with this - you still need to provide Storable hooks for that, no?

      Yes, you need hooks, but with Alter it is easy to provide one generic set of hooks that any class can inherit or even import. All it has to do is give the corona (a normal Perl hash) to the dumper, or to restore the corona of a given object. The equivalent is harder to do with inside-out objects where the object itself (all the dumper gets to see) bears no traces of its data.

      It's like this: Primitive old-style objects tatoo their data on their skin, one tatoo over the other if classes demand. The highly sophisticated inside-out objects store their data in bank vaults on small lexical islands, each in a different class. Hard to trace in case of a sudden death. Alter-stype objects collect their data in a secret pouch with neat compartements for each class, always together, but easy to keep apart.

      Anno

        Thus the mechanism is: Equip each object (magically) with one hidden hash, its corona. Use that hash, keying by class name, to store the individual alter ego of the object for each class.

        This reminds me of another "make inheritance work" technique I'd heard of. Every object is a hash ref (as usual), but every class has their own key into it. Basically every object looks like the $corona in clinton's description. The Alter advantage over that method is mainly privacy. The various classes sharing space can't meddle with each other's attributes. If ego is changed to address tye's concern (so that a class can specify its own name), I'm guessing that Alter loses that advantage too. At that point, you might as well write a base class with ego in it.

          ...reminds me of another "make inheritance work" technique I'd heard of. Every object is a hash ref (as usual), but every class has their own key into it. Basically every object looks like the $corona in clinton's description. The Alter advantage over that method is mainly privacy.

          No, the point isn't privacy, it's being out of band. The corona is attached as a piece of magic to the object which remains free to be anything. That keeps the actual object body uncommitted, a requirement for black-box inheritance.

          Privacy is only secondary, its lack has never been a big deal in Perl OOP (or other Perl, for that matter). The problem isn't that one class can access another's data, the problem is that there is nothing else for it to access. Inside-out and Alter are different ways of addressing that problem.

          Anno

        Thanks Anno, that makes a lot of sense

        I would be interested to understand more about Tye's concerns and how valid they are.

          I would be interested to understand more about Tye's concerns and how valid they are.

          The focus of Tye's concerns is the fact that the ego() function uses its caller to decide which alter ego to produce. Here, "caller" means the package that was in force when the call to ego() was compiled. Now, it is possible to do things like

          package Foo; sub Bar::method { my $ego = ego($_[0]); ... }
          That would indeed produce an anomaly: A method in class Bar that accesses the ego belonging to Foo. On the other hand, that would be the described behavior, for better or worse. It isn't something that easily happens by accident while you're writing your accessors. It may even be useful in some situations, I haven't thought about it much. In general, the Alter-approach assumes that methods are compiled in the class their name resides in.

          Tye has another objection which I'm not sure I understand. If I understand it right it is about qualified method calls, in the form

          $obj->Class::method(...);
          but I think an Alter-based class would behave exactly as it should with these.

          Anno