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

Dear fellow monks

Some days last week I was working on a project of mine and I came across an old problem: that of providing private, protected and public methods and attributes. Ok, nothing difficult: it's very easy and also the camel book shows some examples of how to do it; for instance, to have a private method one could do this check on top of the sub:

{ my $caller = caller ; die unless $caller eq __PACKAGE__ ; }

Also, wanting private attributes, one could create a "class registry" array, and bless a reference index. Like:

package MyClass ; my @Registry ; my $id = 0 ; sub new { my $class = shift ; my $objID = $id++ ; $Registry[$objID] = { some => 'attribute', goes => 'here' } return bless \$objID,$class ; }

From outside (I mean, from other packages), one could not use $$object to get to data, while inside the object one could use an accessor like:

sub some : lvalue { my $self = shift ; # Do checks if we are a private or protected method # HERE! return $Registry[$$self]{some} ; }

(One should provide a DESTROY to get rid of object data when the object is destroyed, of course).

The problem came out when I tried to generalize the approach. I would like to create, say, something like Class::Struct and have my class export some functions, say private and protected, so that I could say:

package MyClass ; use Class::Bronto ; # Sorry, can't find a meaningful name! private 'scalar','priv' ; protected 'array','prot' ; public 'hash','pub' ;

and having a private scalar attribute named 'priv' and so on created along with suitable accessor methods and constructor

The question is: how can I create such a class? What private and fellows are supposed to do to create a good constructor and accessors?

Don't misunderstand me, I'm not looking for directions on Exporter's direction or to CPAN modules to read the code from. I know I could take a peek into the code of Class::Struct and Tie::SecureHash, but I'm taking a different approach. Instead of peeking into someone else's code, I would like to have general suggestions on how to accomplish what I am trying to do, and try to do it myself. If I'll succeed, I know I'll have a good lesson learnt. If I'd read other's code, I know I'll end in use the tricks and forget them some days later. So, if you are willing to help me, don't write too much code ;-)

I already read the camel book and tried some different approaches from which I already learnt a lot. Unfortunately, none of these approaches satisfied me for different reasons. For example, the "class registry" is good for simplicity, but bad for other reasons; the "blessed closure" approach is great, but a bit difficult to read, and I like readable code a lot!

Any advice?

Thanks in advance

--bronto

# Another Perl edition of a song:
# The End, by The Beatles
END {
  $you->take($love) eq $you->made($love) ;
}

Replies are listed 'Best First'.
Re: Looking for exportable privacy and protection
by broquaint (Abbot) on Jul 09, 2002 at 12:33 UTC
    For a simple implementation of private attributes and methods you could just use lexicals e.g
    my %attributes; my $method = sub { ... };
    Of course that would mean that any method which uses a 'private' attribute is also a closure, but you're using a recent version of perl right? If you wanted increased readibilty you could use Sub::Lexical (it'll be on CPAN any day now, honest!). Or you could perhaps write your own source filter to provide such syntactical niceties. There's also a bunch of stuff on the monastery about encapsulation and the like.
    HTH

    _________
    broquaint

      Thanks for your reply, broquaint

      Unfortunately, it was the only one and your pointers didn't give me the information I was looking for.

      The approach in 178518 was quite similar to my "registry" approach: have object variables hidden out of scope. Rather, I found the approach in Attribute::Protected really interesting. It was one of my choices: using subroutine attributes. But I had no idea on how to mark a sub with Private, for example, and make it automatically callable only by the same package. Nor I knew of Attribute::Handlers.

      Ok, now I have a direction for my research. Anyway, I would like some advice on different approaches:

      • a-la-Class::Struct, with exported functions that install accessors by means of eval
      • using subroutine attributes, and perhaps variable attributes (still experimental in 5.8?)
      • installing methods on the fly using AUTOLOAD and *{$AUTOLOAD} = sub { do { this() and that() } } ;
      • ???

      Thanks again

      --bronto

      # Another Perl edition of a song:
      # The End, by The Beatles
      END {
        $you->take($love) eq $you->made($love) ;
      }

        a-la-Class::Struct, with exported functions that install accessors by means of eval
        Perhaps, but Class::Struct may not be the best module to base your OO interface on since it's intent is to implement C structs in Perl. That and eval is evil ;)
        using subroutine attributes, and perhaps variable attributes (still experimental in 5.8?)
        It'd certainly look very nice syntatically, but I believe attributes are still somewhat of a grey area (esp. for variables).
        installing methods on the fly using AUTOLOAD and *{$AUTOLOAD} = sub { do { this() and that() } } ;
        This is certainly a nice way of generating accessor methods if somewhat heavy-handed (*anything* could be an accessor).

        Unfortunately there is a fundamental flaw to this whole approach - it is *impossible* to have truly encapsulated classes in Perl without taking advantage of lexical scoping. So while closures may look like an abberation in your otherwise pristine code, it may be a necessity to achieve your goal of true encapsulation. I think I'll write a meditation on the whole subject of encapsulation in perl in the next week or so.
        HTH

        _________
        broquaint