I wrote PerlX::Maybe precisely for this purpose!
use v5.14;
use strict;
use warnings;
use PerlX::Maybe;
package Foo {
use Moose;
has foo => (is => 'ro', default => 'whatever');
}
my $value = 'hello';
print Foo->new(maybe foo => $value)->dump;
$value = undef;
print Foo->new(maybe foo => $value)->dump;
As you can see, the maybe keyword is applied at the "consumer side" - i.e. in the code that is using the class.
Within the class itself, you could try MooseX::UndefTolerant though that has a major caveat listed in the documentation!
package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name