R – How to define private or internal methods in object oriented Perl

oopperlprivate-methods

I'm using Damian Conway's "inside-out" objects as described is his wonderful book Perl Best Practices to construct an object-oriented interface to a security system at my client. I'm coming across the need to use internal helper methods within my module that I would normally designate as "_some_method". However, this seems to break encapsulation since they can be called directly via the package name. Is there any way of making these methods truly private? As an example,

use SOD::MyOOInterface;

my $instance1 = SOD::MyOOInterface->new();
$instance1->_some_method;  #this produces an error: 
SOD::MyOOInterface::_some_method;   # this results in a 
                                    # successful method call 

Obviously I don't want the direct call of _some_method to succeed. Is there any way of guaranteeing this?

Best Answer

Don't use the PBP for object practices. It is very old. In fact, now the best practices regarding Perl and objects can be found in Moose, an almost must-have for Perl.

In short, the way Perl blurs namespaces and classes most methods can be called statically on the class. This is not a bad thing, just don't document it. There is really no reason to want to seal the methods into the instance. Not having private methods is kind of annoying but the convention of not relying on undocumented methods is so strong it has sufficed for our community.

A trait is effectively a role (doesn't permit instantiation) that can be compiled into an object at runtime. This will further obscure the origin of the methods from your typical user (because they won't be in the original class), but it comes at a runtime cost. See MooseX::Traits for more information on traits.

The prepending underscore is a great convention to further state the method is private to peering eyes.

As a last note if you really want to push this issue, you might be able to create an anonymous class with those methods using Class::MOP::Class->create_anon_class()