our: パッケージ変数へのエイリアスの宣言


凄く今更。

[こっち](https://qiita.com/bunzaemon/items/92f97dcee9b23800e797)の記事を書いたついでに。`our` での検索上位を占めているページに思う所があったので書いとく。[^1]

[^1]: と言ってもこのページが検索上位に上る訳ではないだろうから、抑止にはならんだろうけど。もっと言えば、単なる自己満足


*「〜な変数の宣言」と書かれた場合の一般的な受け取り方としては、「これこれこう言う機能を持った変数です、との宣言」として受けとるだろう。本稿もその前提で記載する。*

<br>

## 主張

`our` の機能は、巷で良くタイトルにされる「パッケージ変数の宣言」ではない。[^2]

[^2]: もちろん、そのページの中身では、きちんと解説されている場合もある

`our` の機能は、該当レキシカルスコープ内で、「***パッケージ変数へのエイリアスを宣言する***」だけのものである。

<br>

つまり、`our $h` とすれば、そのパッケージのパッケージ変数(通常は`main` なので `$main::h` )へのエイリアスを宣言し、パッケージ名 (`main::`) を省略可能にする。

それ以上でも以下でもない。

<br>

## パッケージ変数の宣言

では、パッケージ変数の宣言は、どうするのか？

*パッケージ変数(`$Foo::bar`) は最初に使われたときにひょっこり現われる*[^3] もので、*完全に修飾された変数* [^4] である為、`use strict` のエラー対象外となるもの。そのため宣言は必要ない。

[^3]: `perldoc -f our` より
[^4]: `perldoc strict` より。この訳語はどうかと思うが、要は UNIX のパスで言えばファイルへのフルパスに相当するのが、「完全に修飾された」という言葉。相対パスに相当するものはない。

強いて言えばパッケージ名自体が宣言の様なものだ。

`our $h` がパッケージ変数の宣言と言われるのは、

1. たまたま、`$main::h` を先に弄ってなくて、
2. `our $h` を実行したと同時に `$main::h` がひょっこり現われた

だけ。

パッケージ変数に宣言は必要ない。(2回目)

<br>

***no warnings; no strict; 時***

改めて書くのもアレだが、`no warnings; no strict;` での(宣言無しの)新たな変数は全て、パッケージ変数(`$Foo::bar`)だ。もっと言えば、`our` を省略した [^5] パッケージ変数のエイリアス。

[^5]: もちろん、実装時系列的には正しい説明ではない

```
# no warnings, no strict の場合
% perl -le '$s = 10; print $main::s;' -M-warnings -M-strict
10
```


<br>

## ついでに、 local について

パッケージ変数(`$Foo::bar`)関係なので、`local`も取り上げる。

*"local" はリストアップされた変数を、囲っているブロック、 ファイル、eval の中で、ローカルなものにします。*[^6]

[^6]: `perldoc -f local` より

で、変数関連と特長は、

1. 事実上、パッケージ変数専用
2. ダイナミックスコープ[^7]を取る

[^7]: [perldoc perlfaq7](https://perldoc.jp/docs/perl/5.14.1/perlfaq7.pod#Whats32the32difference32between32dynamic32and32lexical32-40static41-32scoping63-32Between32local40-41-32and32my40-41-63)参照

である。

変数の相関関係で言うと

```
.
+-- パッケージ変数($Foo::bar)        # our でエイリアス作成可能
|    +-- local 変数
+-- my 変数
+-- state 変数
```

の様な形。

で、パッケージ変数専用と意識すると、`local` が ダイナミックスコープであるのは自明となる。


例文で書かれがちな ↓ の様な記載は、

```
#!/usr/bin/env perl
no strict;
no warnings;

sub test () { print $var . "\n";}

$var = 100;
test();
{
    local $var = 10; 
    test();
}
# output
# 100
# 10
```

パッケージ名を明記するだけで、レキシカルスコープであると考える事自体が、パッケージ変数の存在意義を否定してしまう事が分る。

```
#!/usr/bin/env perl
use strict;
use warnings;

sub test () {  
    # レキシカルスコープとしたら、ここで以下の様に直接書く事は出来ず
    # @_ 経由の引渡しが必要となってくる。
    # そうすると、パッケージ変数自体のメリットは皆無となってしまう。
    print $main::var . "\n"; 
}

$main::var = 100;
test();
{
    local $main::var = 10;
    test();
}
# output
# 100
# 10
```

<br>


## 再び、 our について

さて、`our` に戻り、多少の挙動例を記載して本稿を締める。

レキシカルスコープを跨いで複数回宣言するのはダメ。

```
% perl -le 'package test; $test::s = 10; our $s; { our $s; print $s; } print $s;' -Mstrict -Mwarnings
"our" variable $s redeclared at -e line 1.
	(Did you mean "local" instead of "our"?)
10
10
```

前の `our` のスコープが消滅してれば、`our` しても良い。

```
# OK: 跨いでないから 
% perl -le 'package test; $test::s = 10; { our $s; print $s; } our $s; print $s;' -Mstrict -Mwarnings
10
10
```

`local` した後に `our` しても、`our` した後に `local` しても OK[^8]

[^8]: `local` の説明を加えたのは、このワンライナーのため


```
% perl -le 'package test; $test::s = 10; { local $test::s = 100; our $s; print $s; } print $test::s; 1;' -Mstrict -Mwarnings
100
10

% perl -le 'package test; $test::s = 10; {  our $s; local $s = 100;  print $s; } print $test::s; 1;' -Mstrict -Mwarnings
100
10
```



<br>