DEV Community

Cover image for True private attributes and methods for modern Perl OOP
🌌 Sébastien Feugère ☔
🌌 Sébastien Feugère ☔

Posted on • Edited on

True private attributes and methods for modern Perl OOP

Today we will continue our exploration of modern Perl OOP. Those are very experimental features, but I feel like it could be a bit similar to what Corinna could look like so I find it fun to try new things. This is also an opportunity to learn more about OOP.

This is an example of how to implement private attributes and methods with the Zydeco toolkit. We will also see how polymorphism and named parameters works for the needs of this example.

There are other OO modules plugins that allow to add privacy features, but in Perl, it is interesting to see that, privacy is often mostly by convention: subroutines are prefixed with an underscore (e.g. sub _super_private { ... }) and everybody will consider it as private. See a short explanation about this on perlmaven.com in the Public and private methods section.

use v5.20;
use strict;
use warnings;

package DevTo {
  use Zydeco;
  class Privacy {

    # Predeclaration of the accessor coderef
    my $hidden_attr;

    has wonder ( isa => Str );
    has hidden (
      isa => Str,
      is => private,
      accessor => \$hidden_attr );

    method $innaccessible_method {
      say "No problem acessing " . $self->wonder .
      ' through a private method';
    }

    method $innaccessible_method_attr {
      $self->$hidden_attr('a hidden place');
      say "No problem accessing a private attribute in " .
      $self->$hidden_attr;
    };

    multi method no_problem {
      $self->$innaccessible_method;
    }

    multi method no_problem( Bool *with_attr ) {
      $self->$innaccessible_method_attr;
    }
  }

  my $access = DevTo
    ->new_privacy( wonder => "a public attribute" );

  $access->no_problem;
  # ==> "No problem acessing a public attribute through a private method"
  $access->no_problem({ with_attr => true });
  # ==> "No problem accessing a private attribute in a hidden place"

  # This would fail
  # $access->$innaccessible_method;

  # No things are not possible
  # $access->hidden_attr;
  # $access->$hidden_attr;
}
Enter fullscreen mode Exit fullscreen mode

So, what are we doing here?

The privacy with Zydeco can target two different entities:

  • attributes, by using the is => private during the attribute declaration
  • methods, by prefixing the method name with a $

We have two private methods, that we will call from the public multi no_problem() method. This one is declared two times, with different signatures and prefixed with the multi keyword: it makes possible to setup the polymorphism, dispatching the desired behavior depending on the passing of a boolean or not:

# Would call $inaccessible_method
$access->no_problem; 

# Would call $inaccessible_method_attr
$access->no_problem({ with_attr => true });
Enter fullscreen mode Exit fullscreen mode

Note how named attributes are declared and easily used:

multi method no_problem( Bool *with_attr ) { ... }
Enter fullscreen mode Exit fullscreen mode

By prefixing the parameter name with a * and not a $ in the method signature, you get automatic parameter names ready for later

Then, we create a new Privacy object that we call $access. Privacy got a public attribute, wonder and one that is private, called hidden. With Zydeco, declaring an attribute as "private" make it assessor-less. Under the hood, if you check on of the underlying technologies that power Zydeco, it doesn't mean that the attribute is totally inaccessible: we can request an accessor as a coderef.

my $hidden_attr;
has hidden (
  isa => Str,
  is => private,
  accessor => \$hidden_attr );
Enter fullscreen mode Exit fullscreen mode

And then access the attribute in the scope of the variable as follows:

$access->$hidden_attr;
Enter fullscreen mode Exit fullscreen mode

Outside the variable scope, the attribute will be totally invisible. This is possible thanks to a handy technic that allows to call methods dynamically.

References

Top comments (0)