ourの正確な定義

社内でperlのmy,our,localについて盛り上がったのでそのあたりに関するポスト。
今回は、ourについて。

いろんなサイトでいろんな書き方されてて、よーわからん、、ということで ... perldoc
きちっと追ってくと、ああ納得。
少しでも役に立つかなっと、記事としてまとめてみました。
少しでも役立ったときには、コメントいただけるとものすごく喜びますw

ではまず、perldocから。 ここね Perldoc - our

our associates a simple name with a package variable in the current package for use 
within the current scope. When use strict 'vars'  is in effect, our lets you use declared 
global variables without qualifying them with package names, 
within the lexical scope of the our declaration. 
In this way our differs from use vars , which is package scoped.

([意]訳)
"our"は、宣言された現在のスコープの中で、現在のパッケージ変数を
簡単な名前で呼べるようにしてくれます。
つまり、"our"で宣言されたレキシカルスコープ内では、パッケージ名で修飾することなく、
その識別子名でパッケージ変数が呼び出せます。
これは、パッケージスコープのuse varsと異なり、レキシカルスコープであるという所が要チェック。

なるほど、、 Package Foo の中で、our $a としたら、
そのパッケージ変数 $Foo::a をレキシカルスコープ(主に、'{' から '}' まで)では、
$a だけでアクセスできるようになるってことね。

Unlike my, which both allocates storage for a variable and associates a simple name 
with that storage for use within the current scope, our associates a simple name with 
a package variable in the current package, for use within the current scope. 
In other words, our has the same scoping rules as my, but does not necessarily create
 a variable.

([意]訳)
"my"は、変数( $a )のためにメモリに領域を確保し、
変数( $a )がその領域を指し示すよう割り当てておくが、
"our"は、現在のパッケージのパッケージ変数( $Foo::a )を、
変数( $a )が指し示すように割り当てる。

つまり、 "our"はレキスカルスコープであるという点は"my"と同じであるが、
かならずしも、変数を新たに作るわけではない。

ここで言いたいのは、レキシカル空間に変数名は作るけど、それはパッケージ変数へのエイリアスなんだよ、ってことだと思う。
すでにパッケージ変数 $Foo::a が存在していれば、その $Foo::a へのエイリアスとなる。
これが分かると、以下のような挙動も理解できるようになる。

package Foo;

my $a = 1;
print $a;        # 1
print $Foo::a;  #undef;

our $a = 2;
print $a;       # 2
print $Foo::a; # 2

#おもしろいことに...
our $b = 2;
print $b;       # 2
print $Foo::b; # 2
my $b = 1;    # (※)
print $b;       # 1 
print $Foo::b; # 2

簡単にいうなら、 "our"はレキシカルな変数"を作成し(既に存在していたら新しく作成する!)、
同名のパッケージ変数へのエイリアスを割り当てる。

ちなみ、(※)の部分では、use warningsを指定しておくと、

"my" variable $b masks earlier declaration in same scope at /tmp/test.pl line **

という警告が出力される。
myという宣言は一回しかしてないのにもかかわらず、である。
warningsは、 変数名がレキシカルに既に存在しているか、をチェックすることになっている(ような)ので、
このような警告文がでることになる。(と思われる)

An our declaration declares a global variable that will be visible across
 its entire lexical scope, even across package boundaries. 
The package in which the variable is entered is determined at the point
 of the declaration, not at the point of use. 

This means the following behavior holds:

([意]訳)
"our"によって宣言されたグローバル変数(パッケージ変数)は、まさにレキシカルスコープである。
従って、パッケージスコープではないので、パッケージスコープの違いを乗り越えられる。
(ファイルスコープは乗り越えられないが...)
この"our"が有効になるのは、 our $a と宣言したときであって、
その宣言文がかかれたPackageをuseしたときではない。

だから、次のような挙動となる。

レキシカルスコープですよ、ってこと。
"my"とかもpackageの壁を乗り越えられるしね、一緒だよと。
その、「次のような挙動」を見てみると。

package Foo;
our $bar;       	# ここからレキシカルスコープの終わりまで、$barは$Foo::barを指し示す
$bar = 20;

package Bar;
print $bar;             # こいつも $Foo::bar => 20 だよ!

ちゃんとpackageの壁を超えてくれます。

Multiple our declarations with the same name in the same lexical scope are allowed
 if they are in different packages. 
If they happen to be in the same package, 
Perl will emit warnings if you have asked for them, just like multiple my declarations. 
Unlike a second my declaration, which will bind the name to a fresh variable, 
a second our declaration in the same package, in the same scope, is merely redundant.

([意]訳)
同じ変数名に対する、複数回の"our"宣言は、パッケージが違えば許可されています。
もし、同じパッケージ内でやってしまったら、 my 宣言を複数回したときのように警告を発します
但し、新規の値を割り当てる二回目の my 宣言とは異なり、
二回目の our 宣言は、ほとんど変化はない。

同じ変数に対してのour宣言も、パッケージが違うと、その変数が指しているパッケージ変数は変わっちゃうよってことです。
次のスクリプトを見ると、その挙動が一目瞭然です。

package Foo;

my $tmp = 20;
my $tmp;             # warning => 'my' variable $tmp masks earlier declaration....
print $tmp;           # undef

our $bar = 20;
our $bar;             # warning => 'our' variable $bar masks earlier declaration....
print $bar;           # 20 ( not undef )

package Baz;

$Baz::bar = 30;
print $bar;           # 20 ( $Foo::bar )

our $bar;
print $bar;           # 30 ( $Baz::bar )

perldocでは、続いて attribute の話になっていくのですが、
今回は our の挙動を知るということで、そちらはまた別の機会に。

って、perldoc読まなきゃなってほんと思いますね。きっちり書いてある。うん。
最近、英語がボトルネックになってきてるぞ、うーん、苦手っていってられないぞ、、うーん :-(