UNIVERSAL::isa

便利なメソッド UNIVERSAL::isa は、呼び出しに使ったオブジェクトのクラスが、指定したクラスと同じクラス、または継承しているか(is-a の関係かどうか)を確かめる事ができます。
例えば $a->isa("B") と書いた場合、$a オブジェクトが B クラスのオブジェクトか、もしくは B クラスを継承しているオブジェクトである場合に真を返します。
また、クラスに限らず $a->isa("ARRAY") や $a->isa("HASH") などと書けば、配列であるか、ハッシュであるか、などを確かめる事ができます。
コードを書いてみます。

package Rectangle;
sub new {
    my ($class, $width, $height) = @_;
    my $self = { width => $width, height => $height };
    bless $self, $class;
}
sub area {
    my $self = shift;
    return $self->{width} * $self->{height};
}
 
package Square;
@ISA = qw(Rectangle);
sub new {
    my ($class, $side) = @_;
    $class->SUPER::new($side, $side);
}
 
package main;
my $shape = Square->new(5);
print "The area of the shape : ", $shape->area, "\n";
if ($shape->isa("Rectangle")) { print "The shape is-a Rectangle.\n" }
if ($shape->isa("Square"))    { print "The shape is-a Square.\n" }
if ($shape->isa("Triangle"))  { print "The shape is-a Triangle.\n" }

Square クラスは Rectangle クラスを継承しています。つまり、Rectangle(長方形) is-a Square(正方形) の関係です。
$shape には生成した Square オブジェクト(1辺が5の長さ)を代入しています。
以下が実行結果です。

The area of the shape : 25
The shape is-a Rectangle.
The shape is-a Square.

$shape は Rectangle であり、Square でもありますが、Triangle ではない、という事がわかりますね。
isa メソッドはある特定のクラスに対してだけ処理したい場合などに使うと便利ですね。isa を使うと、特定のクラスの子クラスであるかどうか、まで確かめてくれるので、意識せずにポリモーフィズムによって子クラスも扱えます。


can や isa を勉強した限り、UNIVERSAL はとても便利に思います。
ですが、その反面 UNIVERSAL を気軽に拡張するのは危険だと感じます。他の人が書いたコードを読んでいて「このメソッドはどういう意味だろう」と思った時、普通ならそのクラスの定義を読むはずですが、UNIVERSAL クラスで定義されているメソッドは見つける事ができないからです。UNIVERSAL なメソッドは脈絡なく登場するのです。
なんだか、C言語の goto を思い出します。上手く使えば良いコードが書けますが、使いすぎるのは危険、という事でしょうか。