Subject: | Moose::Roles required() ignoring methods that happen to be imported |
Methods which are imported are ignored by a role for the purposes of
satisfying require(). I've attached code to demonstrate. I believe I
see the rationale, you want to avoid calling methods which are actually
accidentally imported functions, but it causes many difficult to debug
problems.
1) The error message gives no indication what's going on.
It pretends the method doesn't exist.
'Role' requires the method 'this' to be implemented by
'InnocentBystander'
This is very confusing as C<< InnocentBystander->can("this") >>.
There's no indication that the method is there but has been rejected. I
had to dig all the way down inside with() to figure this out wasting a
lot of time.
If nothing else comes out of this ticket, the error message should
clearly state that the method exists but was not up to Moose's standards.
2) Makes Moose::Role difficult to integrate into existing systems.
In my case I'm converting a legacy app to Moose. It implements
something like roles using Exporter. These are some of the scariest and
most important parts of the code. Naturally I'm starting around the
edges. I converted a mis-designed "base" class into a set of roles, but
it won't work with the rest of the system. My choice is to Moosify the
entire system at once, contrary to good sense and my client's patience,
drop requires(), or not use Moose::Role. None of these options are
pleasant, and they are worse than the possibility of accidentally
picking up an imported method.
In an attempt to protect me, Moose::Role has made the situation worse.
3) Breaks can().
If you want to know if a class or object implements a method, you call
can() on it. This simple abstraction has always been and works well.
Moose::Role goes around this and peeks inside the class to find out what
it can do. This breaks a class' encapsulation, not only for imported
methods but also for AUTOLOADed methods.