Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Private Methods Meditation

by theAcolyte (Pilgrim)
on Jul 19, 2004 at 04:08 UTC ( #375455=perlmeditation: print w/ replies, xml ) Need Help??


Private Methods (as I understand them)
A private method is unaccessible to anthing other then the owning package. The programmer's intent is to keep other objects/scripts from using these methods.

I imagine these methods need to know things that subclasses shouldn't/wouldn't know, or if called at the wrong time/place could mess up the object in ways that would make your head explode. Violently.

 

How can I make private methods?
Perl has no built in contruct to make methods private and I initally thought this was a good idea. If I _really_ want to use a method you consider private I should be able to. And if it makes my program crash or sing Three Dog Night songs then, its my problem.

The ways I've found to 'fake' private methods involve using code references. I didn't come up with these ideas myself, but saw them mentioned in different posts -- well, the first one anyway. And the second is an extention of the first. I'm calling these:

  • Very Private Methods
  • Private but not really private Methods

Very Private Methods:
you can simply put a code reference in a lexically scoped (I hope I'm using that term right) variable ... like my $method. Here's an example:

package SomeObject; my $very_private = sub { ... } # ------------------------------------------ # to call this method: $self->$very_private();

This method is only callable from within the package the subroutine is in. $object->$very_private(); won't work from wherever you actually created the object, so this fits the description of a private method. However, I'm not really thrilled with making it ~impossible~ to reach in and use it so I tried:

Private but not really private Methods:

package SomeObject; our $Semi_Private_Method = sub { ... }

Now we've got a method that's easy to call within the package that defines it ($self->$Semi_Private_Method();) but can also be called from outside if you REALLY want to ....

$self->$package_of_method::Semi_Private_Method();

 

Which one to use?
Well, all this fiddling around left me with this conclusion: NEITHER. I understand wanting to have private methods, and making it impossible for an inheriting class to accidently override them ... but I enjoy the idea that I can get at private stuff if I really want/need to.

So ... after all of this I decided on an old standard. Private sub names prefixed with an _ and, to prevent an inheriting class from accidently overriding a private method ... name them _packagename_subname.

I know a lot of programmers insist that you need private methods, but thats like saying 'I expect programmers using my class to be idiots'. And, well, if they're idiot, then too bad. :P

theAcolyte
On the Journy to Object Orientedness

Comment on Private Methods Meditation
Select or Download Code
Re: Private Methods Meditation
by Zaxo (Archbishop) on Jul 19, 2004 at 04:35 UTC

    A fair degree of privacy is gotten by constructions like you discuss. You have very well described the use of closures for private data and methods.

    What I really applaud is your conclusion. Perl is not an enforced OO language. Like C++, it is a mixed language with support for OO but no requirement. Unlike C++, perl's OO constructs get by with conventions about what methods may be called reliably. We name private methods with a leading underscore, and we don't care what happens to people who call them from outside.

    This voluntary cooperative model of OO gives the screaming horrors to Smalltalkers and other purists, but it leaves a lot of space for us to work in. Mixed model languages are so much more comfortable to work in. The design of a program does not have to be pounded into any One True Shape.

    After Compline,
    Zaxo

      I often hear perl programmers say stuff like " We name private methods with a leading underscore, and we don't care what happens to people who call them from outside." and other stuff relating to not enforcing privateness in objects. I used to think this was a good thing, a benefit of perl, after all, if he really wants to do that, shouldn't he be able?

      Thats completely missing the point though. The point of private methods and data *isn't* to enforce your "one true shape" on any programmer that tries to use it, the point is so that you can inherit from it without worrying about what the hell your parent class did.

      Perl's object instance data is the main part that suffers from lack of privateness, anything you do in the child class with specifically affect the parent class, so if you want to use a specific key in your child hash, you'd better hope the parent doesn't, at any time, want to use this key! Sure theres some work arounds, but this is perl, we aren't supposed to have to take the long, unwieldy, verbose way to do stuff. It's supposed to be short, succint and to do what we mean.
      This voluntary cooperative model of OO gives the screaming horrors to Smalltalkers and other purists, but it leaves a lot of space for us to work in.

      Most versions of Smalltalk do not actually have any notions of public/private/protected in the way Java/C++ does. Instead Smalltalk's notion of private methods is very similar to perl's, "If you weren't invited, don't come in". Smalltalk has things called method categories, which in the language are really are nothing more than syntactic sugar, but when you combine it with the Smalltalk environment, in particular the Smalltalk code browser, you have another layer of organization between the class-level and method-level. Typically Smalltalk programmers will put all their private methods into the "Private" category. Some Smalltalk implementations will complain (the equivalent of warn) when you call a method that is prefixed with an _ from outside of your class, but none (at least that I know of) will actually enforce this and not let you compile your code. Here is a link that goes into more detail if you are intetested.

      -stvn

      This voluntary cooperative model of OO gives the screaming horrors to Smalltalkers and other purists ...

      I assume that was meant in jest. This Smalltalker is not especially bothered by voluntary cooperation. I'd rather enable than restrict.

Re: Private Methods Meditation
by adrianh (Chancellor) on Jul 19, 2004 at 09:23 UTC
Re: Private Methods Meditation
by castaway (Parson) on Jul 19, 2004 at 10:21 UTC
    The one true "Camel" book (aka. Programming Perl) describes your first method exactly, as a way in which one can make really private methods using Perl, should one want to do that.

    I also agree with the conclusion though, and the books nice anology: Perl doesn't keep you out of its space with a shotgun, it assumes you will respect its boundaries anyway. (probably misquoted ,) Module programmers should do the same..

    C.

      "Perl would rather you stay out of its living room because it asked you, not because it has a shotgun."
Re: Private Methods Meditation
by dragonchild (Archbishop) on Jul 19, 2004 at 12:15 UTC
    Here's the question I ask - why do private methods fail in Perl's implementation of them? It's because of the following situation:
    package Foo; sub new { bless {}, shift } sub _method1 { print "Foo::_method\n"; } sub method2 { my $self = shift; $self->_method1 } package Foo::Bar; @ISA = qw( Foo ); sub _method1 { print "Foo::Bar::_method\n"; } package main; my $foobar = Foo::Bar->new; $foobar->method2;

    The code is being called from within the Foo class, but method lookup finds the _method1() within the Foo::Bar class. *shrugs* I'm not sure where this leads, but that's the reason why. :-)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      Perhaps just

      sub method2 { my $self = shift; _method1( $self ); }
      or am I missing something really obvious in this example ?

      Or for better general safety, mark the privates to make their names unique.

      package Foo; sub _F_method1 { print "Foo::_method\n"; } sub method2 { my $self = shift; $self->_F_method1; } package Foo::Bar; @ISA = qw( Foo ); sub _F_B_method1 { print "Foo::Bar::_method\n"; } package main; my $foobar = Foo::Bar->new; $foobar->method2;

      update: s/exclusive/unique/

        sub method2 { my $self = shift; _method1( $self ); }

        or am I missing something really obvious in this example ?

        Yes. If you don't override _method1 in the subclass, nothing will be called.

        ----
        send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.

      If you're inheriting from someone else, you're mucking around with their internals.

      If you're uncomfortable doing so, then you shouldn't be inheriting.

        tilly, you have a tendency to toss out statements like that without explaining what you mean (that's not intended as criticism.) Are you stating that all OO languages are like this? Clearly you are referring to more than just a blessed referent. With much tighter encapsulation available with Java or C++, do you mean even these languages have the programmer automatically mucking with internals upon subclassing or is this a peculiarity of Perl (or dynamically-typed languages)?

        Cheers,
        Ovid

        New address of my CGI Course.

      I too am bother with this and I shrug when I see     $self->_private(@args)
      because hardly ever has the author documented &_private so I have to be extra careful when extending it and writing my own help routines.

      And I really cry when I see     $self->_init(@_);
      in the parent class after trying to debug a totally innocent subclass, which happened to have a little help routine called &_init.

      IMHO, it's just not particularly clever to call a "private" method as a method since you don't need the method dispatch to find the subroutine, plus you risk being accidently overridden.

      Private methods should be invoked as (help) functions, because that's what they are.     _private($self => @args)
      is my preferred style.

      ihb

Re: Private Methods Meditation
by stvn (Monsignor) on Jul 19, 2004 at 15:38 UTC

    I think you may be missing the point of private methods (I know I did at first).

    The programmer's intent is to keep other objects/scripts from using these methods.
    IMO, It is not so much about using as it is about seeing, and not so much for other scripts/object as it is for subclasses of your object. Private methods can clutter the namespace of a class, which is not usually a problem until you try to subclass it. At that point the use public/private encapsulation policies can be very useful. In C++ and some other OO languages this gets even messier when you introduce things like protected methods, virtual methods and other such insanity. But do keep in mind that these things were all invented for a good reason, and are still in use because they are very useful in certain situations, and you may just not yet encountered that situation.

    I know a lot of programmers insist that you need private methods, but thats like saying 'I expect programmers using my class to be idiots'. And, well, if they're idiot, then too bad. :P

    I (mostly) agree with this. The way I view it is that the "public" methods provided by a class are in essence the contract that the object provides to the outside world. I see contracts as two-way, I (as the user of the class) need to fufill my end of the contract (don't touch the private methods) in order to use your class.

    However, there is a huge problem today with software reliability, and building really good, really reliable and really flexible software components is still a black art, and one that very few people/companies can really get right (and more importantly sustain, it does me no good if its not updated). Whole methodologies have sprung up that are partially an attempt to fix/address these problems (Design by Contract, Test Driven Development, etc etc etc). IMO, if you are releasing your code, anything you can do to secure it, and assure that it performs as advertised is a good thing. And keep in mind that this means breaking and die-ing in all the right places as well, that is an oft under-developed part of many modules.

    Personally I just put an _ in front of my private methods and a comment tell people "This is private, use at your own risk". However, I do find the need sometimes for protected methods (ones that can only be accessed by subclasses), and for that I use this minimal Design-By-Contract inspired snippet:

    sub _my_protected_method { ((caller)[0]->isa(__PACKAGE__)) || die "This method can only be called by a subclass"; # ... do something }
    This just ensures that it is only called from within its own package or a subclass of itself. And again, its not so much for the users of the class as it is for those who are subclassing. In this case, I want to provide the ability to use a method that I would not normally want in my "public" interface, and since I cannot easily "hide" it from view, I make the choice to enforce this with extreme predjudice.

    To be honest, I usually don't feel that method encapsulation is a big issue. However, encapsulation of instance data is another issue (which you addressed this in your previous post). For that I use the module I created (Devel::StrictObjectHash), which works somewhat like use strict in that it really just serves to keep you from shooting your own foot off.

    -stvn

      Personally I just put an _ in front of my private methods and a comment tell people "This is private, use at your own risk".
      Tell me, do you also document it? If you do, you belong to an extremely small minority.

      ihb

        Tell me, do you also document it?

        Do you mean document, as in comments? Almost always yes, unless the code itself is so glaringly obvious that it needs no documentation.

        If you mean document, as in POD? Then the answer is sometimes. Documenting private and protected methods in POD is only really useful for those who want to subclass your module, and I try to make sure to point that out when I do so as not to confuse.

        -stvn
        Why would someone want to document private methods?

        Documentation is a promise that something won't change. Part of the point of keeping private methods private is that they might change in future versions. Those goals are in conflict with each other.

Re: Private Methods Meditation
by stvn (Monsignor) on Jul 19, 2004 at 15:42 UTC

    You might find this paper (its a PDF) interesting, it is by the same group that brought us Traits. It talks about adding a more flexible encapsulation policy to Smalltalk (it's concepts though are applicable to most dynamic OO languages (perl, python, etc)).

    The author discusses the idea that many times you need more than one encapsulation policy. The simplest example being; one for public use, and one for use by subclasses (which would be roughly equivalent to public and protected), but they take it to the next level really. Interesting read.

    -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://375455]
Approved by Zaxo
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (9)
As of 2014-08-23 03:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (172 votes), past polls