🌌 Sébastien Feugère ☔
Posted on March 20, 2021
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;
}
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 });
Note how named attributes are declared and easily used:
multi method no_problem( Bool *with_attr ) { ... }
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 );
And then access the attribute in the scope of the variable as follows:
$access->$hidden_attr;
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
Posted on March 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.