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

Fellow Monks

I currently use a constructor a la:

sub new { my $class = shift; my $self = { FLYBEHAVIOUR => undef, QUACKBEHAVIOUR => undef, }; my @protected = qw/FLYBEHAVIOUR QUACKBEHAVIOUR/; my @private= qw//; my $closure = sub { my $field = shift; grep( /$field$/, @private ) and caller(0) eq __PACKAGE__ || confess "$field is private"; grep( /$field/, @protected ) and caller(0)->isa(__PACKAGE__) || confess "$field is protected"; if (@_) { $self->{$field} = shift; } return $self->{$field}; }; bless( $closure, $class ); return $closure; }

to have private and protected fields in my classes.

I am wondering if there exists a faster way? What do you fellows think?

I particulary like this way. The $self explains ifselve and the two lists called @protected and @private make it clear that what's defined and mentioned in either list is either private or protected

But perhaps I need another OO model in Perl. If someone could point out what inside-out classes would provide I'd be grateful.

--
if ( 1 ) { $postman->ring() for (1..2); }

Replies are listed 'Best First'.
Re: A quicker way to have protected and private fields?
by xdg (Monsignor) on Feb 28, 2006 at 21:28 UTC
    I am wondering if there exists a faster way?

    What do you mean faster? Faster to write? Faster to run? Faster to read and understand? What are you trying to optimize for, or is this just a thought exercise?

    I'd generally suggest using any of a number of class generating tools -- these usually have syntax which are fairly self documenting. Personally, I don't find that protected functions are really common in Perl unless you're an OO purist.

    However, protected fields are already supported by Object::InsideOut, and in five statements of code:

    package My::Class; use Object::InsideOut; my @FLYBEHAVIOUR :Field( 'Accessor' => 'FLYBEHAVIOR', 'Restricted' => +1 ); my @QUACKBEHAVIOUR :Field( 'Accessor' => 'QUACKBEHAVIOR', 'Restricted' + => 1 ); 1; # modules need to return true

    Is that fast enough for you?

    Implementing protected fields is somewhere on the TODO list for Class::InsideOut. However, if all you want is public/private, the syntax is similarly short and very readable:

    package My::Class; use Class::InsideOut ':std'; private FLYBEHAVIOR => my %FLYBEHAVIOR; private QUACKBEHAVIOR => my %QUACKBEHAVIOR; sub new { register( bless \(my $scalar), shift ) } 1; # modules need to return true

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: A quicker way to have protected and private fields?
by BMaximus (Chaplain) on Feb 28, 2006 at 21:09 UTC
    Read through the documentation for Class::Std. It has what you're looking for. Here's an example.
    package SomeClass; use strict; use warnings; use Class::Std; { # Attributes my %whatever: ATTR; # this initializes the class in place of new sub BUILD { my ($self, $ident, $arg_ref) = @_; ... # Do some initialization stuff here } # here's a method that's private. It throws an exception when call +ed from outside the class it's declared. sub some_method: PRIVATE { my ($self) = @_; ... # Some class stuff here } }


    BMaximus
Re: A quicker way to have protected and private fields?
by Roy Johnson (Monsignor) on Feb 28, 2006 at 21:25 UTC
    At a minimum, you want to change your greps from doing pattern matching to doing string equality. If there's much chance that the list of values to search will grow beyond a handful, it would be advantageous to use a hash instead, for faster lookups.

    Is it likely that you will have different protected and private members on a per-object basis, or would it make more sense to move those definitions outside the constructor?

    This is an interesting way to implement objects. I can't see that it's particularly advantageous, but it is interesting.


    Caution: Contents may have been coded under pressure.
Re: A quicker way to have protected and private fields?
by chromatic (Archbishop) on Feb 28, 2006 at 19:51 UTC

    Inside-out classes would let you subclass your objects, for one. You'd also have to write much less code.

      But I can subclass already by doing:

      In the case of this strategy pattern I don't think I would gain much. Maybe you know of other cases?

      --
      if ( 1 ) { $postman->ring() for (1..2); }

        Suppose I want to subclass your original class to add a single attribute. What does the code look like to do that? What does the code look like to use the object?

Re: A quicker way to have protected and private fields?
by gargle (Chaplain) on Mar 01, 2006 at 07:50 UTC

    Here's the complete code, after a little change in the constructor method. I dropped the lists and implemented the protected and or private access as a field in the $self hash. It's an implementation of the strategy pattern (yeah, just bought the Head First Design Patterns).

    --
    if ( 1 ) { $postman->ring() for (1..2); }