MidLifeXis has asked for the wisdom of the Perl Monks concerning the following question:

Wise ones...

I have been playing with ideas I have read in relation to InsideOut - hiding object data inside of a lexical block within a class. I have been trying to bind the data even more tightly to the methods. However, since DESTROY() needs to be called for proper housekeeping, I am finding it difficult to accomplish.

I have searched the tomes here, but have not been successful in finding what I am looking for. Feel free to point out where I have missed :)

What I have

I know that this is not complete - I mean look at the names of the variable ;). Bugs with data checks aside... (thanks diotalevi ;)

use strict; use warnings; package testhiding; sub new { bless [], shift; } { my %foo = (); my %bar = (); sub foo { my $self = shift; my $new = shift; my $old = $foo{$self}; $foo{$self} = $new if defined($new); $old; } sub bar { my $self = shift; my $new = shift; my $old = $bar{$self}; $bar{$self} = $new if defined($new); $old; } sub DESTROY { my $self = shift; delete $_->{$self} for (\%foo, \%bar); } } 1;

What I would like

use strict; use warnings; package testhiding; sub new { bless [], shift; } { my %foo = (); sub foo { my $self = shift; my $new = shift; my $old = $foo{$self}; $foo{$self} = $new if defined($new); $old; } } { my %bar = (); sub bar { my $self = shift; my $new = shift; my $old = $bar{$self}; $bar{$self} = $new if defined($new); $old; } } # XXX - Where does this go then... sub DESTROY { my $self = shift; delete $_->{$self} for (\%foo, \%bar); } 1;

I know why DESTROY does not work, that is not the problem. I would like to make DESTROY work somehow. The structure to allow that while also allowing the tighter coupling of the data to the methods is where I am getting stuck.

Any ideas?

Update: Lack of data checking and bugs in the code acked. Since that isn't the intent of the question, take all code as a sample, not as should be written, etc. :)

Replies are listed 'Best First'.
Re: InsideOut - even tighter coupling
by demerphq (Chancellor) on Oct 10, 2003 at 17:58 UTC

    Just add an additional scope, sub and var for the DESTROY method to use as a register of things it needs to work with.

    { my %register; sub DESTROY { my $self=shift; delete $_->{$self} foreach values %register; } sub __register_inside_out { my $ref=shift; $register{$ref}=$ref; } } { __register_inside_out(\(my %property)); sub property { my $self=shift; if (@_) { $property{$self}=shift; return $self; } return $property{$self}; } }

    HTH


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


      Thank you. That is the part I was missing.

Re: InsideOut - even tighter coupling
by diotalevi (Canon) on Oct 10, 2003 at 17:51 UTC

    The fastest and most immediate is to make %foo and %bar package variables. Your methods live as package globals, there's no reason their data can't as well. I wouldn't solve this that way though. You're typing a lot of the same things more than once. You also have a bug - you've not accounted for passing in the undef value.

    my %Vals; for ( qw(foo bar) ) { my $method = shift; *$method = sub { my $self = shift; my $old = $Vals{$method}{$self}; $Vals{$method}{$self} = @_ ? $_[0] : (); return $old; }; }

    Oh yes, I nearly forgot (this is an update). The destroy method. Also, explicit return values are a virtue. It gives you something to expect instead of just having undefined behaviour (which leaving that delete on the end would certainly have done).

    sub DESTROY { my $self = shift; delete $_->{$self} for values %Vals; return; }

      I definitely agree on all points. I am using the easiest chunk of code I know of to try to play with a different problem. Thanks for the feedback on coding style.

Re: InsideOut - even tighter coupling
by yosefm (Friar) on Oct 13, 2003 at 07:39 UTC
    I'm just interested: how will methods access other private variables, and if you even want that in your code?

    If you only use methods as accessors, then this is not a problem. but if your methods actually do something useful, they often need access to private variables. And then what?

    I see a lot of nodes here on PM that treat methods as accessors only, which is defenitely not the case in good OOP, IMO.

      However, good OOP code encapsulates all member variables with accessor/mutators. Great OOP code uses that encapsulation internally. There are few instances where direct access to private members are needed internally. In 9 out of 10 cases using an accessor/mutator internally will suffice. This practice allows your objects to be as flexible with regard to implementation internally as they are to external objects.

      The moral of this story. When writing your Class, treat your class as you would an external class. It all comes back to the Golden Rule: Treat others as you want to be treated. hmm... It even works for programming =]

      This approach leads to a more flexible Object Model, and when implementations change you will find yourself typing less code.
      ( Because we all know that programmers are lazy =] )

        This practice allows your objects to be as flexible with regard to implementation internally as they are to external objects.
        Indeed. In particular, it makes a subclass author's life much easier when an object doesn't rely on its own implementation structure any more than absolutely necessary.

        Makeshifts last the longest.

      That is actually what I am working on, how tightly can you (or, I guess, can I) couple variables to their accessors / mutators, and still be able to make it usable. I am especially interested in avoiding name collisions on the private variable stash when using inheritance. I think this is going to do the trick.

      The problem I ran into was with the DESTROY method. That issue was cleared up by running a registration method on the private variables.

      I will try using this in a couple of small things, and see how well it scales for me.