忘れた頃に出てくるPerlのエラーメッセージのコーナー。
今回は
"our" variable %s is redeclared
である。
Akoya pearl
これはSVCの形式の英文だ。
(S:主語)"our" variable %s/our変数%sは
(V:動詞)is/である
(C:補語)redeclared/再定義された

redeclaredは動詞redeclareの過去分詞系である。
redeclareはdeclare(定義する)にreを付けたもので、再定義された、という意味になる。

Perlではuse strict "vars"を書かないと、宣言なしに変数を登場させることが出来る。
しかし、use strict "vars"を書いて、変数について厳しい姿勢でプログラミングに臨むことを宣言すると、変数は以下のいずれかである必要がある。

 ・$_、@INCのようにmainパッケージにもともと備え付けの変数
 ・myで宣言されたレキシカル変数
 ・ourで宣言されたグローバル変数
 ・$Find::File::nameのような完全修飾名

なお、use strictには他にuse strict "refs"(シンボリックリンクの禁止)、use strict "subs"(裸のワードの禁止)がある。
単にuse strict;と書くと"vars"、"refs"、"subs"が一挙に禁止される。
プログラムを書くときは常にuse strict;およびuse warnings;(ちょっとしたことでも警告する)を常にオンにして、あらゆる診断メッセージを出すようにしておくのがおすすめだ。

さて、ourで宣言されたグローバル変数とはなんだろう。

プログラム例を挙げる。

#! /usr/local/bin/perl
# sumNumbers.pl --- 数字を加算する

use strict;
use warnings;

use MyNumUtil;
use 5.10.0;

my @num = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
my $sum = &MyNumUtil::sumNumbers(@num);
say "配列の合計は", $sum;
say "MyNumUtilのバージョンは", $MyNumUtil::version;

# MyNumUtil.pm --- 数字のユーティリティ関数集(現状は1個)

package MyNumUtil;

use strict;
use warnings;

our $version = "1.0";

sub sumNumbers {
 my $sum = 0;
 for (@_) {
  $sum += $_;
 }
 return $sum;
}

1;

実行するとこうである。
C:\Perl\perl>sumNumbers.pl
配列の合計は55
MyNumUtilのバージョンは1.0
モジュールMyNumUtil.pmに入っている数字を加算するサブルーチンsumNumbersを使って、1から10まで加算してみた。
答は55だ。
便利だなー。

sumNumbers.plはメインプログラム、MyNumUtil.pmはモジュールファイルである。
簡単のため、これら2つのファイルは両方ともC:\Perl\perlという同じフォルダーに入れるとする。
(上のプログラム表記は全角スペースでインデントを表現しているので注意)

さて、上のプログラムには、先に述べた変数の4パターンがすべて入っている。

まず、

 ・$_、@INCのようにmainパッケージにもともと備え付けの変数


 for (@_) {
  $sum += $_;
 }
の中で@_(サブルーチンの引数を参照する変数)、$_(いろいろな用途があるが、ここではforループの制御変数を省略したときに制御変数になる)を使っている。
いずれもPerlの設計によって備え付けられている変数である。

 ・myで宣言されたレキシカル変数

はメインプログラム、モジュールの両方で定義された$sumがそうだ。
これらはそれぞれ、自分が定義されたスコープの中でしか参照できない。
メインプログラムの$sumはファイルsumNumbers.pl全体である。
モジュールの$sumはサブルーチンMyNumUtil::sumNumbersの中である。
これらは同じ名前だが赤の他人であり、別のメモリ空間に格納される。
だから安心して使えるのである。

さて、

 ・ourで宣言されたグローバル変数
 ・$Find::File::nameのような完全修飾名

はペアで使う。

モジュールファイルで宣言した変数をメインプログラムでも使いたいとき、モジュールファイルの中ではour宣言して、メインプログラムではそれを完全修飾名(FQN:Fully Qualified Name)で参照する。

上のプログラムでは、MyNumUtil.pmの中で
our $version = "1.0";
とour宣言したのを、sumNumbers.plの中で
say "MyNumUtilのバージョンは", $MyNumUtil::version;
とFQNで使っている。
これでMyNumUtilモジュールの変数を、useするプログラムに露出することが出来る。

では今日のお題のエラーメッセージはどうやったら出せるだろうか。
(別にエラーメッセージなんか出したくないが・・・)
こうしてみる。
# MyNumUtil.pm --- 数字のユーティリティ関数集(現状は1個)

package MyNumUtil;

use strict;
use warnings;

our $version = "1.0";
our $version = "1.1";

sub sumNumbers {
 my $sum = 0;
 for (@_) {
  $sum += $_;
 }
 return $sum;
}

1;
太字の部分が余計である。
実行してみる。
C:\Perl\perl>sumNumbers.pl
"our" variable $version redeclared at MyNumUtil.pm line 9.
配列の合計は55
MyNumUtilのバージョンは1.1
MyNumUtil.pmの中のour変数$versionが、2回定義されたので2回目が警告されている。
これは警告で、プログラムはちゃんと実行され、計算結果55と共に、2回目の方のバージョン番号1.1が表示されている。

こんな失敗するのかいなという気もするが、長い複雑なプログラムを書けば、そういうことも起きるかもしれない。