Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
There is more than an answer to this question.

  • One way is to use a lexical reference to a method:

    pl@nereida:~/LEyapp/examples$ cat #!/usr/local/bin/perl -w use strict; { package Tutu; my $_tutu = sub { my $self = shift; "Inside tutu. My class is ".ref($self)."\n" }; sub plim { my $self = shift; print "plim can access _tutu as a private method:\n" .$self->$_tutu; } sub new { bless {}, $_[0]; } } package main; my $obj = Tutu->new(); $obj->plim();
    Now the $_tutu method is visible only inside the closure enclosing the Tutu package.
  • Most of the time the sort of privacy we need is to avoid a descendant class accidentally overwriting a private method. In such case, calling the method as a subroutine Class::_private_method($self) instead of using the $self->_private_method syntax will suffice.
  • You can have a sort of dynamic visibility of methods beteween classes in the same hierarchy (but only one level of inheritance) using the strategy of naming a lexical CODE reference inside the client methods
    #!/usr/local/bin/perl -w use strict; package Tutu; my $protected = sub { my $self = shift; "inside Tutu::tutu!\n" }; sub plim { my $self = shift; local *protected = $protected; print "Accessing 'protected' as a method: " .$self->protected(); } sub new { bless {}, $_[0]; } package SubTutu; our @ISA = qw{Tutu}; # SubTutu can overwrite 'protected' sub protected { my $self = shift; "inside overwritten tutu!\n" }; package main; my $obj = SubTutu->new(); $obj->plim(); print(Tutu->can('protected')? (Tutu::protected()."\n") : "main does not even know of 'Tutu::protected'\n" ); $obj->plim(); # Let us provoke an exception Tutu::protected();
    When executed gives the following output:
    $ Accessing 'protected' as a method: inside overwritten tutu! main does not even know of 'Tutu::protected' Accessing 'protected' as a method: inside overwritten tutu! Undefined subroutine &Tutu::protected called at ./attributeprotectedwi line 49.

  • A problem with Attribute::Protected is that the universal method "can" still see the methods qualified as private.
    When you run the following code:
    pl@nereida:~/LEyapp/examples$ cat #!/usr/local/bin/perl -w package SomeClass; use Attribute::Protected; sub foo : Public { } sub _bar : Private { } sub _baz : Protected { } sub another { my $self = shift; $self->foo; # OK $self->_bar; # OK $self->_baz; # OK } sub new { bless {}, $_[0] } package DerivedClass; @DerivedClass::ISA = qw(SomeClass); sub yetanother { my $self = shift; $self->foo; # OK $self->_bar; # NG: private method $self->_baz; # OK } package main; my $some = SomeClass->new; $some->foo; # OK print ($some->can('_bar')?"Yes, main can see that SomeClass has a _bar + method\n":"no\n");
    produces the following output:
    $ Yes, main can see that SomeClass has a _bar method
    But certainly the purpose of Attribute::Protected is to warn you as soon as possible of the crash rather than hide the method
  • Unfortunately -at the time of this writing - Sub::Lexical seems to be broken with modern versions of Perl. See the test results at CPAN
  • Let me tell you a story:

    I wrote Parse::Eyapp a LALR compiler compiler (s.t. similar to Parse::RecDescent). From a grammar specification produces an abstract syntax tree. The tree can then be manipulated using an attribute grammar like the one provided by Luke Palmer Language::AttributeGrammar.
    Language::AttributeGrammar was written with Parse::RecDescent in mind and assumes that node children are accesed by name instead than by ordinal number, which is the way used by Parse::Eyapp.
    Language::AttributeGrammar access to children is through a private method called _get_child.
    The fact that the private method wasn't really hidden allowed me to overwrite the method and to restore it after the modification so that if later in the program an attributed grammar - let us say for a Parse::RecDescent generated tree - needs the old version of _get_child it will work. See the pertinent fragment of code for a small calculator:

    94 my $attgram = new Language::AttributeGrammar <<'EOG'; 95 96 # Compute the expression 97 NUM: $/.val = { $/->{attr} } 98 TIMES: $/.val = { $<0>.val * $<1>.val } 99 PLUS: $/.val = { $<0>.val + $<1>.val } 100 MINUS: $/.val = { $<0>.val - $<1>.val } 101 UMINUS: $/.val = { -$<0>.val } 102 ASSIGN: $/.val = { $::s{$<0>->{attr}} = $<1>.val; $<1>.val } 103 EOG 104 105 { 106 # rewrite _get_child, save old version 107 no warnings 'redefine'; 108 *Language::AttributeGrammar::Parser::_get_child = sub { 109 my ($self, $child) = @_; 110 111 $self->child($child); 112 }; 113 114 my $res = $attgram->apply($t, 'val'); 115 } 116 # Restored old version of Language::AttributeGrammar::Parser::_ge +t_child
    Paraphrasing Larry Wall's quote, This is like going into the living room, changing a bit the things while none is using them, and cleaning and restoring them after use so that the next visitors will find them where they expect. If the living room were totally locked (I.e. if Luke Palmer decided to use a solution like the lexical closure reference above for _get_child) we couldn't do it.
    As someone else said, Perl's motto "Don't enter my private spaces unless invited to do so" carries an invisible caveat: "or you really need to".

In reply to Re: REALLY Private Methods in perl: Is Perl Flexible enough to be made Inflexible? by casiano
in thread REALLY Private Methods in perl: Is Perl Flexible enough to be made Inflexible? by penguin

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (8)
As of 2021-06-16 14:26 GMT
Find Nodes?
    Voting Booth?
    What does the "s" stand for in "perls"? (Whence perls)

    Results (75 votes). Check out past polls.