5つめのカテゴリーは「エラー メッセージ蒐集」です。
 『かんたんPerl』では、プログラムを間違えてエラー メッセージを出すこと、そのエラーをどうやったら潰せるかにこだわって書いています。普通うまくいく例を書く本は多いのですが、間違いとその直し方について読むのも勉強になるのではないかと思って書きました。巻末にはエラー メッセージ索引も付いていますので、本と同じエラーが発生した時は参照してください。
 と、書いてはみたものの、『かんたんPerl』で紹介しているエラーはそんなに多くありません。そこで、ブログのこのコーナーでは、いわゆるラクダ本こと『Programming Perl』の巻末についている付録「診断メッセージ」からエラー メッセージを抽出し、どんなプログラムを書けばこのエラーが出るのか、どうやれば直るのか、実験をしてみようと思います。エラー メッセージであまりこういうものを見たことがないので、役立つかどうかはさておくとして、珍しいと思うので読んでください。なお、お断りですが、このコーナーの最初の方は、ぼくの雑記ブログ『イジハピ!』に書いた内容の焼き直しになります。まあ、文章を少しよそ行きに、ブラッシュアップしようと思っています。

 第1回は「"%s" variable %s masks earlier declaration in same %s」です。

MaskeAgamemnon

 ここで%sはString(文字列)を意味するプレースホルダーで、任意の文字列が入ります。では、このエラー メッセージが出て来るプログラムを書いてみましょう。

#! /usr/local/bin/perl
# maskDecl.pl -- 変数の二重定義

use strict;
use warnings;
use 5.010;

my $i = 3;
say "\$iは$iです!";

my $i = 5; # 11行目
say "\$iは$iです!";

 では早速実行してみます。

[sample]$ ./maskDecl.pl
"my" variable $i masks earlier declaration in same scope at ./maskDecl.pl line 11.
$iは3です!
$iは5です!

 早速出ましたね。
 これはエラーではなくて警告です。警告をしてくるものの、一応プログラムは実行され、完走しています。use strict;を取っても表示されますが、use warnings;を取ると表示されません。
 実行例を見ると、3つの%sが、「"my"」、「$i」、「scope」に展開されていることが分かります。
 実行例の方を翻訳してみると「./maskDecl.pl line 11において、my変数$iが、同じスコープのより早い定義を覆い隠している」という意味になります。

 これは、my変数$iの宣言が2回登場したから怒られているので、一方の名前を変えたら起こりません。

#! /usr/local/bin/perl
# maskDeclFixed.pl -- 変数の二重定義を解消した

use strict;
use warnings;
use 5.010;

my $i = 3;
say "\$iは$iです!";

my $j = 5;
say "\$jは$jです!";

 さあどうだ。

[sample]$ ./maskDeclFixed.pl
$iは3です!
$jは5です!

 治りましたね。ま、当たり前ですね。このコーナー基本的にこういうアホみたいな感じで進行するので覚悟してください。
 さて、最初の間違っていたプログラムは、間違っているなりに完走したんですが、2回めのmyが無効になったのか(同じ$iが使いまわされているのか)、それとも最初のmyが無効になったのか($iという変数がもう1個定義されたのか)気になりますね。ここでは変数のリファレンスというものを使って調べてみましょう。

#! /usr/local/bin/perl
# maskDecl_2.pl -- 変数の二重定義その2(リファレンスで調査する)

use strict;
use warnings;
use 5.010;

my $i = 3;
my $iref = \$i;
say "\$iは$iです! \$iのリファレンス\$irefは$irefです";

my $i = 5; # 12行目
my $iref_2 = \$i;
say "\$iは$iです! \$iのリファレンス\$iref_2は$iref_2です";

say "さっきの\$iref($iref)が指すメモリーの値は以下のとおり:", $$iref;
 リファレンスは『かんたんPerl』では出て来ず、『すぐわかるオブジェクト指向Perl』の最初の議題ですが、C言語のポインターに当たる機能です。

my $iref = \$i;

 ここがミソです。my変数$iを作ると、コンピューターのメモリー空間上に領域が確保されます。この領域のアドレスが$irefに入ります。これを変数$iのリファレンス(参照)と言います。
 では、変数$iが持っている値を、$irefを使って取り出すにはどうすればいいでしょうか。つまり、リファレンス$irefが指し示すメモリー空間が保持している値を取り出すということになります。これは以下のようにします。

$$iref

 これをリファレンス$irefのデリファレンス(参照解決)と言います。これは、$irefがスカラーを指しているリファレンスだから頭に$が付きました。リファレンスは配列、ハッシュ、サブルーチンも参照できますが、それをデリファレンスするのはまた別の記法が必要になります。長くなるのでその話は別の機会で。
 では、上のプログラムを実行します。

[sample]$ ./maskDecl_2.pl
"my" variable $i masks earlier declaration in same scope at ./maskDecl_2.pl line 12.
$iは3です! $iのリファレンス$irefはSCALAR(0x7f811b016618)です
$iは5です! $iのリファレンス$iref_2はSCALAR(0x7f811b034a18)です
さっきの$iref(SCALAR(0x7f811b016618))が指すメモリーの値は以下のとおり:3

 まず、当然ながら「2回目のmy $iが1回目のをマスクしている」という警告が復活しました。警告は2回目のmyを行った瞬間に起きます。
 で、1個目の$iは0x7f811b016618という番地のメモリー空間を指し示しているが、2個目のは0x7f811b034a18というもう1つ別のメモリー空間を指し示していることが分かります。つまり、2回目のmyによって別のメモリー空間に$iという変数名が割り当てられました。
 では、1回目のmyによって$iという変数名が割り当てられていたメモリー空間はどうなっているかというと、リファレンス$irefを取っておいて参照解決すると、見事3が出たということは、ちゃんと値が保持されているということが分かります。もう$iという名前では値を取り出せませんが、$irefを使えば参照できます。

 まあ、警告まで出して、こんな面倒なことをわざわざする人はいないでしょう。masks earlier declarationと言われたら、二重定義を、おそらく意図に反して行ってしまっているので、名前を変えて解消するようにしましょう。