How to check if an attribute has a value without directly accessing the internals of the class? Fetching the value and checking if it is undef is not always the right thing. There are cases when the value can be legitimately be set to undef. You might need a different way to check if the value has ever been set.

Setting the predicate key of an attribute to 1, Moo will create a corresponding has_ method that will return true of false, depending weather the attribute has any value (including undef) or not.

For example if we have an attribute called 'name', then predicate => 1 will tell Moo to generated a method called has_name. If we had an attribute with a leading underscore (e.g. _age, then the predicate => 1 will prefix it with '_has' and generate _has_age

Example

Given the following Person.pm module:

package Person;
use Moo;
use 5.010;

has name => (is => 'rw', predicate => 1);

1;

Let's try the following programming.pl file:

use strict;
use warnings;
use 5.010;

use Person;

my $anonymous = Person->new;
say $anonymous->has_name ? 'has name' : 'no name';

my $anonym = Person->new( name => undef );
say $anonym->has_name ? 'has name' : 'no name';

my $student = Person->new( name => 'Joe' );
say $student->has_name ? 'has name' : 'no name';

Running perl programming.pl will give the following output:

no name
has name
has name

In programming.pl we created 3 Person objects and then used say and the ternary operator to print if it 'has name' or 'no name'. As you can see above, only in the first case did has_name return false.

That is, setting the value to undef still means it has a value.

predicate in other word

There might be cases when the has_ prefix is not a good fit. Either grammatically, or because you use the has_ prefix of an attribute to some other task. For such cases, Moo let's you pick your own word by using that word as the value in the attribute declaration:

In Person.pm the attribute declaration changes to this:

has name => (is => 'rw', predicate => 'has_a_real_name');

In programming.pl we also have to update the calls to use the new has_a_real_name method:

my $student = Person->new( name => 'Joe' );
say $student->has_a_real_name ? 'has name' : 'no name';

Once you set an attribute to any value, even undef, you cannot make unset. Well, except if you use a special tool for it called clearer.

clearer

The clearer functionality work really closely together with the predicate. After calling the clearer method of an attribute, it will seem as if that attribute was never set to any value.

Setting clearer => 1; of an attribute, Moo will create a method with a clear_ prefix. For example if the attribute is called name, then the clearer method will be called clear_name.

In Person.pm we have this code:

has name => (is => 'rw', predicate => 1, clearer => 1);

In programming.pl we have this:

my $student = Person->new( name => 'Joe' );
say $student->has_name ? 'has name' : 'no name';

$student->clear_name;
say $student->has_name ? 'has name' : 'no name';

Running perl programming.pl we get:

has name
no name

That is, after calling the clear_name method, the attribute is gone.

Interaction with default

We must ask the question how do these interact with the other options available for attributes. Most notably, what happens if we 'clear' an attribute that has a default value?

The Person.pm has this content:

package Person;
use Moo;
use 5.010;

has name => (
    is        => 'rw',
    predicate => 1,
    clearer   => 1,
    default   => 'Foo',
);

1;

The programming.pl has this:

use strict;
use warnings;
use 5.010;

use Person;

my $student = Person->new();
say $student->has_name ? 'has name' : 'no name';
say $student->name;

$student->clear_name;
say $student->has_name ? 'has name' : 'no name';
say defined $student->name ? 'defined name' : 'not defined name';

The output is

has name
Foo
no name
not defined name

The answer then is that you can totally clear an attribute, the default flag only applies during the construction of the object.

Interaction with required

The same is true with the required flag. That too is only checked during construction. Using a clearer you can still remove any trace of it ever existed in an object.

Person.pm changes to this:

has name => (
    is        => 'rw',
    predicate => 1,
    clearer   => 1,
    default   => 'Foo',
    required  => 1,
);

programming.pl changes to this as we now have to pass a value to 'name' in the constructor:

my $student = Person->new( name => 'Joe' );
say $student->has_name ? 'has name' : 'no name';
say $student->name;

$student->clear_name;
say $student->has_name ? 'has name' : 'no name';
say defined $student->name ? 'defined name' : 'not defined name';

and the out is this:

has name
Joe
no name
not defined name