I've been meaning to write about this gotcha for a long time, but somehow forgot. This was actually an undiscovered bug in Moose for several years:
use strict;
use warnings;
use Test::More;
use Try::Tiny qw(try);
{
package Foo;
use Scalar::Util qw(blessed);
sub new { bless {}, $_[0] }
}
my $foo = Foo->new;
is( try { blessed($foo) }, undef );
is( try { blessed $foo }, undef );
done_testing;
The first test passes. blessed has't been imported into main, so the code results in the error Undefined subroutine &main::blessed.
The second test, on the other hand, fails. This is because blessed has been invoked as a method on $foo.
The Moose codebase had several instances of if ( blessed $object ), in packages that did not import blessed at all. This worked for ages, because Moose::Object, the base class for most objects in the Moose ecosystem, didn't clean up that export, and therefore provided an inherited blessed method for pretty much any class written in Moose.
I think this example provides a very strong case for using namespace::clean or namespace::autoclean routinely in your classes.
To cover the other half of the problem, the no indirect pragma allows the removal of this unfortunate feature from specific lexical scopes.


1 comments:
Good post, short and concise.
How would you fix it using namespace::autoclean?
Will you be pushing no indirect to Moose::Object or the rest of Moose?
Post a Comment