Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re: Beyond Inside-Out (fluff)

by tye (Sage)
on May 29, 2007 at 13:27 UTC ( [id://617957]=note: print w/replies, xml ) Need Help??


in reply to Beyond Inside-Out

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

- tye        

Replies are listed 'Best First'.
Re^2: Beyond Inside-Out (fluff)
by Anno (Deacon) on May 29, 2007 at 14:26 UTC
    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

      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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (5)
As of 2024-04-16 19:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found