4

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 );
}
Haloor
  • 221
  • 4
  • 14
  • 2
    Check this out http://stackoverflow.com/questions/1734385/how-do-i-define-private-or-internal-methods-in-object-oriented-perl – aggaton Jan 06 '17 at 23:48
  • there doesn't seem to me to be any reason not to just call it as `$self->_private_sub(%arg)` – ysth Jan 06 '17 at 23:55

4 Answers4

4

To my knowledge, there's no "correct" way. Perl doesn't provide the ability to hide the functions, at least that I've ever run across. What I've done is use a naming standard where I start the internal-only function names with an underscore and clearly document that they're never to be called by external callers.

EDIT: The other answers triggered a thought. In each private method, you could check the results of the "caller ()" function and abort if the caller is anyone other than the local module. Honestly, I personally wouldn't go to the trouble, but if it's really important to you for some reason, that would emphasize the private nature of these methods.

goug
  • 2,294
  • 1
  • 11
  • 15
3

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 sub 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 odd but that surely warns the users that it is a private method. This makes it hard for subclasses to inherit, thanks to mob for emphasizing this.

The second invocation uses $_private as a function rather than a method, so we have to pass the object if it needs it. This further warns against its use. Then it also doesn't undergo the normal 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 are very useful, but they are not truly private. I use them, liberally.

A full answer is to use Moose or Moo, or some other module.

Community
  • 1
  • 1
zdim
  • 64,580
  • 5
  • 52
  • 81
  • Doesn't that make it hard for subclasses to inherit your private method? – mob Jan 06 '17 at 23:57
  • @mob Well, it does, thus the warning. It still can be a choice, for those that will not be subclassed. Are you saying that it shouldn't be used really (as a matter of "good practices")? – zdim Jan 06 '17 at 23:59
  • 1
    No, but I am saying I just learned that `$sqrt=sub{sqrt($_[0])}; print 9->$sqrt` will actually output 3! – mob Jan 07 '17 at 00:00
  • 1
    @mob Huh ... ?? ... um, it does work! I don't get it (yet -- don't tell me please! :). – zdim Jan 07 '17 at 00:04
  • While you are at it, look up mst's talk *you did what?* on YouTube. :-) – simbabque Jan 07 '17 at 09:48
  • BTW, Moose doesn't help here. It makes everything more convenient, but it is also just Perl. There is hardly any magic involved and it cannot make things private. – simbabque Jan 07 '17 at 09:55
  • @simbabque Thank you, I'll look it up. As for Moose, I didn't think one can make it _truly_ private (but I did hope for something close to it) -- but I mean that it must stimulate a different mind set. I don't use it day to day but I'd expect it to focus one on a far higher level and then it may simply never come to all kinds of picky decisions. (I'm inching toward picking up a module for regular use, toward Moo.) – zdim Jan 07 '17 at 10:39
1

As opposed to $self->_private_sub(...)? In my mind, the $obj->_method notation is always used with function that act on an instance of your class, and other kinds of calls are always used for other kinds of functions.

But if you're going to be paranoid, why not use an unconventional way of packing your arguments that will confound anyone that tries to use your private method in an object oriented way?

sub do_stuff {
    my ( $self, %arg ) = @_;
    ...
    _private_sub( %arg, $self );
}

sub _private_sub {
    my $self = pop;
    my %args = @_;
    ...
}
mob
  • 117,087
  • 18
  • 149
  • 283
  • Alright, this is a real mind-job :) (Just ... they'll probably look it up in the source and still go ahead) – zdim Jan 07 '17 at 00:06
  • That is horrible. Private or not, security through obscurity is hardly a good idea. This will make your maintenance programmer hate you (remember that could be you), and stuff will break every time a user (or you) tries to call that `_private_sub` as a method. Mixing methods and functions in one class should not be the way to go. – simbabque Jan 07 '17 at 09:53
  • I often wish I could upvote my own answers, but yeah, sometimes I wish I could downvote them, too. – mob Jan 07 '17 at 17:33
1

All of the answers you have received so far say that it can't be done. But it can - in Perl 5.18 and later. See the section on lexical subroutines in perldoc perlsub.

Lexical Subroutines

WARNING: Lexical subroutines are still experimental. The feature may be modified or removed in future versions of Perl.

Lexical subroutines are only available under the use feature 'lexical_subs' pragma, which produces a warning unless the "experimental::lexical_subs" warnings category is disabled.

Beginning with Perl 5.18, you can declare a private subroutine with my or state. As with state variables, the state keyword is only available under use feature 'state' or use 5.010 or higher.

These subroutines are only visible within the block in which they are declared, and only after that declaration:

no warnings "experimental::lexical_subs";
use feature 'lexical_subs'; 

foo();              # calls the package/global subroutine

state sub foo {
  foo();            # also calls the package subroutine
}

foo();              # calls "state" sub
my $ref = \&foo;    # take a reference to "state" sub

my sub bar { ... }
bar();              # calls "my" sub

To use a lexical subroutine from inside the subroutine itself, you must predeclare it. The sub foo {...} subroutine definition syntax respects any previous my sub; or state sub; declaration.

my sub baz;         # predeclaration
sub baz {           # define the "my" sub
  baz();            # recursive call
}
Community
  • 1
  • 1
Dave Cross
  • 68,119
  • 3
  • 51
  • 97