Perl Quiz - 解説
解答一覧(敬称略)
- ${^ENCODING}を使う by yappo - いきなりドン引き
- *is = \&isnt; by miyagawa
- *CORE::GLOBAL::ref/pp.cへパッチを当てる - by tokuhirom
- testルーチンの書き換え by wakapon - miyagawa氏のと同タイプ
- package ::Foo by mattn - この解答が今回の動機でした
- $::Foo:: by fbis - mattn氏のと同タイプ
- bless {}, '::Foo' by hakobe932 - mattn氏のと同タイプ
- 偽の結果を出力 by ktat
- eq演算子の戻り値の書き換え by gfx
- ブクマコメント BEGIN{ exit(1) } by kazuhooku
パッケージの「名前」について
mattn氏,fbis氏,hakobe932氏が解答してくれたのが今回のPerl Quizの動機なので,解説します。
まず以下のコード:
#!perl -w { package Foo; package ::main::Bar; } print ref(bless {}, '::Foo'); # => "Foo" (1) print ref(bless {}, 'main::main::Foo'); # => "Foo" (2) print ref(bless {}, 'Bar'); # => "::main::Bar" (3) __END__
Perlはパッケージ名の先頭の"::"を無視するので,"::Foo"という名前でブレスしても実際にブレスされるのはパッケージ"Foo"です。また,"main::"についても同様で,パッケージ名の先頭にいくつ"main::"が付いていようと全て無視されます。
さてここで,同一パッケージであってもプログラムによっては異なる名前を持つことがあります。これは,最初に参照した名前がそのパッケージの名前となるためです*1。それを示すのが(3)です。Barパッケージは確かにBarパッケージとして存在しますが,最初に参照したのが"::Bar"という名前なので,Barパッケージの名前は"::main::Bar"です。しかしその実体はBarパッケージであることに違いはなく,"Bar"という名前でブレスすると,"Bar"と"::main::Bar"が同一パッケージであるということが分かります。
このような仕様のため,ref(bless {}, 'Foo')と'Foo'がいつも真になるとは限らないのです。
なお,UNIVERSAL::isa()はこのあたりの事情を酌んでくれるので,通常はこの仕様が問題になることはありません。