I Hate Cheats

I never liked cheats and while playing with Acme::Moose I figured out I can easily cheat by setting any of my values or peeking at them while I was playing. As we are able to do this sort of thing


my $moose = Acme::Moose->new; 
$moose->feed; 
if ( $moose->happiness ){
...

Of course as my variables are 'rw' this little problem is all my fault.

In the original Acme::Llama the internal global variable hash value


package Acme::Llama;

our %llama;

Which buried it as an internal that someone playing the game could not really get at.
I could of course set up my Acme::Moose the same way but then there would not be much Moose involved in the class and I would be mixing procedural code and OO code.

So I poked around a bit and toyed with a few ideas. One way to simply use the '_' convention on my private attributes (that sounds rude) like this


has [ '_foodage','_happiness','_tired']=> (is=>'rw',default=>0,isa=>'Int',init_arg=>"");
no Moose;

but that doesn't stop someone from doing this


my $moose = Acme::Moose->new; 
$moose->feed; 
if ( $moose->_happiness ){
...

It just tells them if they read to code that this is suppose to be a private attribute.

Well you could also try using separate setter and getter like this


 has 'happiness' => (
      is     => 'ro',
      reader => '_get_happiness',
      writer => '_set_happiness'
  );

They will still be able to read it still and set it as well if they peek behind the scenes at the code. As well I will have to write more code than I have to.

Well obviously someone else has had this problems because there is a Moose::X just for this called MooseX::Privacy.

In my code all I need to do is


use MooseX::Privacy;

has [ 'foodage','happiness','tired']=> (is=>'rw',default=>0,isa=>'Int',init_arg=>"",traits => [qw/Private/],);
no Moose;

and when I try to fiddle things

I get


Attribute foodage is private at C:/Dwimperl/perl/site/lib/MooseX/Privacy/Meta/Attribute/Private.pm line 13
	MooseX::Privacy::Meta::Attribute::Private::_check_private('Moose::Meta::Class::__ANON__::SERIAL::11=HASH(0x3138af4)', 'main', 'foodage', 'Acme::Moose', 'Acme::Moose') called at C:/Dwimperl/perl/site/lib/MooseX/Privacy/Meta/Attribute/Privacy.pm line 31
	Acme::Moose::foodage('Acme::Moose=HASH(0x1781364)') called at moose.pl line 21

There is also few other nice features in this MooseX like "Protected" that makes the attribute available to the class and any sub classed created from if.

As well I can set any method in my class to be as private or protected which will come in handy I am sure.

another-moose-in-your-life1.jpg

1 Comment

MooseX::Privacy is slow; doesn't offer true private methods (in the sense used by Java, PHP, etc); and it's quite trivial to work around...

package Something::Else;
use Acme::Moose;
my $obj = Acme::Moose->new;
my $happiness = do {
   package Acme::Moose;
   $obj->happiness;
};
print "I can see it!!! $happiness\n";

If you want private attributes, use Lexical::Accessor. I'm not saying that it's impossible to work around Lexical::Accessor (it can be done fairly easily via PadWalker), but it's a more proper implementation of method privacy, and doesn't result in bog-slow accessors.

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations