paulymer has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I am new to Moose and came across a scenario that seemed confusing to me. I am wondering if this use case was designed to be this way or if it needs more consideration. Here is my code:

ScoreBoard.pm -------------------- package ScoreBoard; use Moose; use MooseX::Privacy; has 'started' => ( traits => [qw/Bool Protected/], is => 'ro', isa => 'Bool', predicate => 'hasGameStarted', handles => { startGame => 'set', }, ); 1; ScoreBoard-test2.pl -------------------------- #!/opt/local/bin/perl -w use strict; use ScoreBoard; my $sb = ScoreBoard->new; print "Game has not started yet\n" if !$sb->hasGameStarted;

Here is the error message I get when I execute the test script:

$ ./ScoreBoard-test2.pl Attribute started is protected at /opt/local/lib/perl5/site_perl/5.12. +3/MooseX/Privacy/Meta/Attribute/Protected.pm line 13. [snip ...]

As you can see from my module, I created a "Protected" attribute and defined a predicate method 'hasGameStarted' and a delegated method 'startGame'. The program failed due to the interaction between the "Protected" status of the attribute and the predicate method. So I changed my module to the following:

has 'started' => ( traits => [qw/Bool Protected/], is => 'ro', isa => 'Bool', #predicate => 'hasGameStarted', handles => { startGame => 'set', }, ); sub hasGameStarted { my $self = shift; return defined $self->started; }

This time, the program runs successfully and I get the expected output:

$ ./ScoreBoard-test2.pl Game has not started yet

Now, to my point, the part that confuses me. I originally defined the two methods directly under the "Protected" attribute. The predicate method failed, whereas the delegated method succeeded. It seems to me that either they should both fail or they should both succeed. I would prefer that they both succeed personally, but I'm sure I have a very narrow view at this point. My rationale is that the "Protected" status of the attribute is to prevent the caller from accessing the attribute, in this case 'started'. But the caller is calling the '$sb->hasGameStarted' method and at no time ever attempts to access '$sb->started' (that happens behind the scenes in the module, but the caller wouldn't know that directly). It seems logical to me to allow the predicate method. Thoughts? Thanks.

Replies are listed 'Best First'.
Re: Why is the predicate method not available for a MooseX::Privacy protected attribute?
by tobyink (Canon) on Aug 31, 2013 at 15:58 UTC

    It should fail. If the attribute is protected, then it can only be accessed from within the class it was defined in, and from subclasses. Whether to do the same with delegated methods was a design decision made by the MXP authors; there are arguments in both directions, but personally I think they made the right choice. That a method is implemented by delegation is really an implementation detail; code outside the class shouldn't care.

    That said, MXP doesn't really give you proper private methods. To do that, you'd need to delve into the MRO, and MXP was not ambitious enough to do that.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      Thanks for the reply. Everything you said makes sense, but...

      I say "but" because the user experience with this use case is less than desirable. The inconsistency between the failure of the predicate method and the success of the delegated method doesn't satisfy my left-brain needs. So, there's my two cents for what it's worth.

      Also, we could easily apply the same argument to the predicate method as was given for the delegated method, e.g. "That a method is implemented by delegation is really an implementation detail; code outside the class shouldn't care." Whether 'hasGameStarted' is implemented as a predicate or a sub shouldn't matter outside the class. If I'm still missing something, I apologize for belaboring the point. Thanks.