Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re^2: Beyond Inside-Out (fluff)

by Anno (Deacon)
on May 29, 2007 at 14:26 UTC ( [id://617964]=note: print w/replies, xml ) Need Help??


in reply to Re: Beyond Inside-Out (fluff)
in thread Beyond Inside-Out

I'm disappointed that you chose to leave out the heart of your idea, how ego() works.

Sorry. That can be helped :)

ego($obj, $alter) sets the alter ego of $obj to be $alter. When called with one argument, ego($obj) retrieves whatever $alter was in the two-argument call.

The point in this is that ego() is caller-sensitive, so that each class sees its individual Alter::ego() for each object. A class can initialize it to whatever it wants and use it without interference from other classes. No other class can access it (through the official interface), by definition.

In the current implementation the assignment is sticky, it only works once for each class/object combination, but I don't think that's necessary.

In more detail, on the first call (ever) with an object, ego() associates one hash with the object (through ext magic), which is keyed by the caller's class name to store the individual alter ego(s). Later calls from other classes continue to use it.

I like to call this hash the corona because it represents the round of alternative personalities of an object, to stay with the image, and also because it is the overhead. The corona is invisible to the normal class user, but will be made internally available to support serialization through Data::Dumper and Storable.

Anno

Replies are listed 'Best First'.
Re^3: Beyond Inside-Out (details)
by tye (Sage) on May 29, 2007 at 15:00 UTC

    Something like:

    sub ego { $_[0] ||= {}; my $corona= shift @_; my $pkg= caller(); for my $ego ( $corona->{$pkg} ) { $_= shift @_ if @_; $_ ||= {}; return $_; } }

    Yes, a much simpler and more direct solution to some of the problems that "inside-out" objects are being promoted to address1.

    Note that this suffers from the usual short-comings of caller. The calling "package" is quite an ambiguous thing and calller returns only one meaning of that. I have personally written methods that have many different values for the different interpretations of "calling package" and I bet your module would fail in such situations (just like SUPER:: and its replacements fail).

    Consider:

    package Devel::HandyMethods; sub Handy::GetOrSet { my $self= ego( shift @_ ); # ... } package My::Module::_private; *My::Module::foo= \&Handy::GetOrSet; sub My::Module::bar { my $self= ego( shift @_ ); # ... }

    It is unfortunate that caller provides no way to get "My::Module" when Handy::GetOrSet() gets called via "SubclassOf::My::Module"->foo() (assuming @SubclassOf::My::Module::ISA= 'My::Module'). So you should provide ways for module authors to override how you determine which package name to use.

    And thanks for pointing out some of the stupidity of "inside-out" objects. I still boggle a bit that such a convoluted technique for inheriting from objects that were not designed to be inherited from has become the most touted method for doing all Perl OO. Saner alternatives need more touting. (:

    - tye        

    1 Note that "inside-out" objects were first created to address being able to subclass arbitrary objects but "inside-out" objects are now being heavily touted as the way to implement all objects and your idea certainly has a lot of advantages as far as a "best practice" way of implementing objects. But your method doesn't deal with the original "subclass arbitrary object" problem.

    Also, you don't address the "compile-time checking of member variable names" issue that "inside-out" objects address. Some would "use fields" as another solution. I prefer to have an array for an object and use constant subroutines for member variable names.

      Something like:
      sub ego { $_[0] ||= {}; my $corona= shift @_; my $pkg= caller(); for my $ego ( $corona->{$pkg} ) { $_= shift @_ if @_; $_ ||= {}; return $_; } }
      Yes, a much simpler and more direct solution to some of the problems that "inside-out" objects are being promoted to address1.

      Yes, that's similar with one important difference: In your implementation, the object proper is its corona (a hash). The way I have it in Alter, the object itself can be whatever it is, the corona is attached via magic, and accessed through the magical ego() function.

      That leaves the possiblity for the object proper (the "carrier") to be whatever it needs to be to support a conventional class. That answers the question of mixed inheritance. Like with inside-out, any class can inherit from an Alter-based class, and in reverse, an Alter-based class can inherit (without further ado) from one conventional class. Both work by making the conventioonal object the carrier.

      As for method-borrowing, a la

      package Foo; *brrowed_meth = \ &Bar::meth;
      why, yes, the borrowed method would continue to access the alter ego that was established in Bar. That's what I would expect in any case.

      As to the more general problem of the various meanings of caller, if I'm not mistaken what I'm using is the package that was in force when the call to ego() was compiled. That is excatly what I want: Mehods compiled in a class access the alter ego specific to that class, and that's the only way.

      Anno

        what I'm using is the package that was in force when the call to ego() was compiled. That is excatly what I want: Mehods compiled in a class access the alter ego specific to that class, and that's the only way.

        Yes, you are using the package (not "class") that the method was compiled in. But, no, you appear to have nearly completely missed my point. The package that a subroutine was compiled in can have very little to do with the class that the method ends up being a part of. In my example, the "class" you'd end up using isn't even a class, just the name of a package where code for some subroutines happened to be compiled.

        The correct thing to look up is not what package the code was compiled into, nor the package part of the orignal name given to the subroutine (the two things that caller can give you). The correct "class" is the package part of the subroutine name that was used to find the subroutine when the method was looked up (looking in symbol tables and following @ISA). Unfortunately, I have yet to see a way to get this information. That is why you'd need to provide a way to override how the class name is determined.

        Ah, so you are using Perl "magic" and you are allowing for "uncooperative" subclassing. If you'd include the XS code then this would have been clearer. I can't comment much on this because I'd still be guessing at what you are really doing (no, I'm not going to download the package and extract the source this morning), though I consider using "magic" to take much of the "simpler" benefit away from your idea.

        - tye        

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://617964]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (2)
As of 2024-04-19 19:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found