Some time ago (nearly 15 years, actually) in this thread, btrott was talking about various ways of protecting a blessed object and quite a lot of discussion came from it.

I haven't seen anyone suggest using Variable::Magic to achieve this. I'm thinking of writing a base class with a class method on the lines of this.

sub new { my $class = shift; my %params = @_; my $protected = sub { croak qq{Attempt to access protected data "$_[2]"} unless call +er->isa(__PACKAGE__); }; my $wiz = wizard( store => $protected, fetch => $protected, exists => $protected, delete => $protected, ); my %self; cast %self, $wiz; my $self = \%self; bless $self, $class; $self->$_($params{$_}) foreach keys %params; return $self; }

Does anyone have any views on whether this (a) will work correctly and (b) will be useful? The intention is to make the underlying hash inaccessable other than to subclasses of a class using this as a parent.

The main problem I'm trying to solve is the programmer who accidentally types $obj->{field} when he meant $obj->field, thereby inadvertantly bypassing any clever stuff in the getter.

Replies are listed 'Best First'.
Re: Private & Protected Objects
by tobyink (Canon) on Aug 10, 2014 at 20:15 UTC

    Although I agree with the intention, this seems like a bad way to implement it. It seems an unnecessarily black-magic technique to implement a form of protection that can be achieved via easier means.

    If you just want to avoid an accidental $obj->{field} then use blessed-arrayref objects instead of blessed-hashref objects. It will still be possible for people who do $obj->[3] to access a field, but they're less likely to do that accidentally.

    Better yet, use inside-out objects. Although they've gone in and out of fashion, there are some good implementations on CPAN (MooseX::InsideOut, MooX::InsideOut, Class::InsideOut, etc) and the various difficulties associated with inside-out objects (e.g. makes Data::Dumper less useful) are well understood.

    Also, read Method Privacy in Perl - not quite the same topic, but perhaps of interest to you.

Re: Private & Protected Objects
by afoken (Chancellor) on Aug 10, 2014 at 18:25 UTC

    Variable::Magic depends on Perl 5.8. 15 years ago, Perl 5.8 was not even dreamed of. (But I think you know that.)

    I think that Variable::Magic gives you "more than enough rope" to build enforced protected and private objects, among many other strange things. Using magic has its good uses ("white magic"), but for me, using magic to prevent access does not feel right; it's "black magic".

    NOTE in perlmodlib states:

    Perl does not enforce private and public parts of its modules as you may have been used to in other languages like C++, Ada, or Modula-17. Perl doesn't have an infatuation with enforced privacy. It would prefer that you stayed out of its living room because you weren't invited, not because it has a shotgun.

    The module and its user have a contract, part of which is common law, and part of which is "written". Part of the common law contract is that a module doesn't pollute any namespace it wasn't asked to. The written contract for the module (A.K.A. documentation) may make other provisions. But then you know when you use RedefineTheWorld that you're redefining the world and willing to take the consequences.

    I prefer a Perl without a shotgun, so I can mess with object internals when needed for a temporary bugfix or workaround.

    BTW: I think I could bypass your current protection using caller->isa(__PACKAGE__) like this:

    use Third::Party::Class; # uses your constructor package Third::Party::Class { sub bypassPermissions { my ($self,$name,$value)=@_; $self->$name($value); } } my $object=Third::Party::Class->new(...); $object->bypassPermissions(secret => 42);

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      Also, standard access to internals gives you a number of mechanisms for compatibility, etc. One of the things that I like about Moose is that I can pass an object off to a TT template and use it as a hashref.

      The solution to "enforced privacy" is immutability and functional programming. Perl does pretty well there if you are careful.

Re: Private & Protected Objects (Variable::Magic)
by Anonymous Monk on Aug 10, 2014 at 20:05 UTC

    Does anyone have any views on whether this (a) will work correctly and ?

    Sure, why not :)

    Does anyone have any views on whether this (b) will be useful?

    Um, given the many many many things that already exist, maybe

    Can't be faster than restricted hashes ie fields/Hash::Util::lock_keys ... but yeah, fields doesn't force accessors ...

    It goes back to freedom, if the user wants to shoot his own foot with direct access, let him, less work for you :)

    A test :)