UNIVERSAL-can reviews

RSS | Module Info

UNIVERSAL-can (1.12)

I don't like packages which do things in the UNIVERSAL namespace much, but I'm not going to refuse to use a package just because the *tests* (not the running module itself) use it.

In the case of Catalyst, the dependency on Test::MockObject has been removed in the latest version.

UNIVERSAL-can (1.12) *

This changes the behaviour of a core perl distribution (one must include emitting warnings as behaviour).

For that reason alone, it is bullshit. I am uninterested in justifications - talk to the perl pumpkings if you want a change propogated there.

I have read the doc, I understand the reason, I don't like the solution.

This will probably back me out of using Catalyst (which uses T::MO, which uses UNIVERSAL::can).

UNIVERSAL-can (1.12) *

This moduel requires either GPG or Crypt::OpenPGP to install, but doesn't check for them, and there seems to be a bug in the latter, preventing UNIVERSAL::can from installing: the author has been informed.

'gpg' is not recognized as an internal or external command,
operable program or batch file.
Can't locate object method "all_props" via package "Crypt::OpenPGP::Key::Public::DSA" at C:/Perl588/site/lib/Crypt/OpenPGP/Key.pm line 25.

UNIVERSAL-can (1.03) ***

Update: In the months since I wrote the review below, I've become convinced that I was partially wrong. I'll keep the review below intact, but revise my comments.

I think chromatic et al. are right about the problem. The use of UNIVERSAL::can and isa as a function is a very bad practice. I closes several doors for creative implementations of facades and the like.

The right solution to the problem is for everyone write your code like:

print eval { $obj->can('foo') } ? 'yes' : 'no';
The eval is the key that I overlooked when I wrote my earlier review.

However, I still think that the implementations of UNIVERSAL::isa and UNIVERSAL::can are highly unfortunate and aggressive, leading to lots of bad feelings instead of solving the problem. I believe that the authors are trying to solve a legacy and social problem via questionable technical means. My primary complaint is the breakage that arises from the emitted warnings, especially in test code. I really don't want to have to say "no warnings 'UNIVERSAL::can'" in *every* program I write...


This is a poor module that should either be rewritten or moved to the ACME namespace. It's better than it's sibling, UNIVERSAL::isa, in that it's documention is good, but it's still a very bad solution to a known problem.

This module asserts that it's better that programs should crash than that authors call UNIVERSAL::can as a function. The rationale is good -- that calling can() as a function breaks OO-style modules which may override the can() method call -- but given that Perl 5 cannot call methods on unblessed objects means that the functional form is the only useful form of can() without a lot of extra code.

Here's a case where can() called as a function works where the method syntax fails:

my $foo = undef;

print UNIVERSAL::can($foo, "new") ? "yes" : "no"; # prints "no"

print $foo->can("new") ? "yes" : "no"; # dies with "Can't call method "can" on an undefined value"

UNIVERSAL-can (1.03) **

Why would a class override the isa() mechanism? Is it also going to override perl's @ISA-search mechanism to define its own sense of inheritance? Of course not.

In my opinion the fact that can() is a method at all is unfortunate, it should simply have been a language feature like tied() that a class can't override. The various kludges to get things to work for classes to override can() seem to be exhibit A.

Overriding can() is a whole different beast. That's often quite a good idea, especially in cases where the set of methods defined by a class aren't known in advance. But isa() is very different.
2 hidden unhelpful reviews