perloop

How to organize private methods on Perl objects?


What is the correct way to handle methods which will not be called by the user? For example if the user calls a method, say do_stuff() from a driver script, and if do_stuff() relies on other subroutines, is it best practice to call those subs from within the do_stuff() method as follows:

sub do_stuff {
    my ( $self, %arg ) = @_;
    #does it things
    #and then calls the private sub as follows
    _private_sub( $self, %arg );
}

Solution

  • If your do_stuff method needs the functionality that you decided should be kept "private" then by all means call _private_sub within it. That is precisely its purpose. Of course, having a method be "private" is a matter of convention as it cannot be enforced.

    I'd like to mention another way, of using coderefs for private subs

    my $_private = sub { ... };  # must be at least predeclared
    
    sub do_stuff {
        my ($self, %arg) = @_;
        # ...
        my $from_private = $self->$_private(@args);    # or
        my $more_private = $_private->($self, @args);
    }
    

    The syntax is of the first call is odd but then that also warns that it is meant as a private facility. Note that this is a trick of sorts -- while $self is indeed passed as the first argument, one could use any old reference instead of $self and the call works and $_private is passed that.

    Using this makes it harder for subclasses to inherit, thanks to mob for emphasizing this.

    The second invocation uses $_private as a function rather than like a method, so we have to pass the object if it needs it. This further warns against its use. It clearly doesn't undergo any method lookup process (and is thus slightly faster), something to be well aware of.

    I am a little uncertain as to what exactly the question seeks.

    If it is about whether to use "private" subroutines in your code, then there is really no accepted best practice. They can be very useful, of course. But they are either not truly private or, if you hide them as lexicals that cannot be seen from outside the unit (scope) like here, their behavior differs so much that that itself is an issue. I use them, with due care.

    A better approach is probably to use Moose or Moo, or some other module. The organizational conveniences may shift the focus so that issues of "privacy" never come up. Also, a variety of tools and features that come in the ecosystem surrounding them may make it easier to handle special needs. But these libraries do not provide any special magic that would provide "true" private methods ("private" like in some other languages), thanks to simbabque for emphasizing this.


    Introduced in v5.18, and stable since 5.26, we have lexical subroutines. They are defined with my sub ... (or state) and exist only within their lexical scope. So surely nothing outside the file can see them. Go read up and play.

    However, I find that one cannot use them via the method call syntax. I don't know about the design decisions and am not sure why that is, but one cannot do

    # NOPE -- Can't locate object method "lexisubname" via package...
    $self->lexisubname(...)  
    

    unlike for a lexical coderef, which can be called via -> and the caller (a reference) is passed to it, as misleading as that may be. Unless I am missing something, that would restrict the use of lexical subs to a function call, where $self has to be passed in explicitly if needed.


    Related:

    There's got to be more similar pages discussing this.