http://www.perlmonks.org?node_id=576707

When I was at YAPC::2006, a talk of chromatic's got me to thinking about a better way of producing inside-out objects. My idea proved troublesome, but here's the interface I wanted:

use Encapsulation; sub new { bless {}, shift; } sub foo { my $self = shift; return $self->{foo} unless @_; $self->{foo} = shift; } 1;

In other words, I wanted inside-out objects to act like a normal blessed hash. You know, if inside-out objects were that simple, more people would use them. I've stopped using them because they're so painful to me. I was talking about this idea to adrianh and he suggested a different approach than my foolish attempt to use a tied and blessed hash. Then he sent me the code.

#!/usr/bin/perl use strict; use warnings; { package Encapsulate; use Scalar::Util; BEGIN { my $Secrets = {}; use overload '%{}' => sub { my $id = Scalar::Util::refaddr( shift ); my $package = caller; return $Secrets->{ $id }->{ $package } ||= {}; }, fallback => 1; sub DESTROY { my $id = Scalar::Util::refaddr( shift ); delete $Secrets->{ $id }; }; } } { package Foo; use base qw( Encapsulate ); sub new { my $class = shift; return bless {}, $class; } sub foo { my $self = shift; $self->{ secret } = shift if @_; return $self->{ secret }; } } { package Bar; use base qw( Foo ); sub bar { my $self = shift; $self->{ secret } = shift if @_; return $self->{ secret }; } } use Test::More tests => 6; isa_ok my $o = Bar->new, 'Bar'; $o->foo( 42 ); is $o->foo, 42, "can set and get value of Foo's secret"; Bar->new->foo( 24 ); is $o->foo, 42, "different objects get different secrets"; $o->bar( 99 ); is $o->bar, 99, "can set and get value of Bar's secret"; is $o->foo, 42, "secrets of different classes do not interfere"; ok !defined $o->{secret}, 'cannot reach into objects';

It's not complete (no serialization support, for one thing), but wow, that's pretty easy! So go ahead, shoot holes in this approach.

Cheers,
Ovid

New address of my CGI Course.