パッケージ変数(配列・連想配列)へのもう一つの値の入れかた


凄く今更。
Perl で新規スクリプトを書く予定もないし、こんなコードを使う気もない。
ただ、記憶の奥底に沈めた訳分らんコードが目についた以上、放置するのは奥歯にものが
挟まったみたいで嫌だったので。

本稿のプログラムは全て `use strict; use warnings;` の下、動作します。

<br>

[2024/07/08]

本稿は、結局は型グロブを利用してました。ってだけの記事です。

なので、本稿を読むより、型グロブの本格的な解説記事を読まれる方が良いかと思います。

<br>

## 発端

```
% perl -le '0->[0] = 100; print 0->[0];' -Mstrict -Mwarnings
100
```

え、、、何これ。[^1]

[^1]: どこぞのページで見付けたコードから。古いページだし、解説もされてないし、敢てリンクしません。

左辺値が裸の `0` で始まってるのに、怒られてないよ？
何でリファレンスなの？
`B::Deparse` したら `$0[0]` のことだって。何でこう書けるの？

<br>

## 利用している機能

***配列・連想配列の型グロブ(`*Foo::Bar`)利用時に、何にアクセスするか自明の場合は `*` を省略出来る模様。その代りクォーテーションで括る必要がある。*** [^2]

[^2]: 但し、perldoc 内でそれらしき説明には行きあたっていない


型グロブで、`%main::h` へ値の代入。print 時には `->{}` でハッシュにアクセスしているのは明白

```
% perl -le '*main::h = { 10, 11} ; print *main::h->{10};'
11
```

なので、以下の様に記載出来る。

```
% perl -le '"main::h"->{10} = 11 ; print "main::h"->{10};'
11
```

時々、CPAN モジュールの中とかで見られる書き方ではあるけど、普通は使わない。

<br>

### 型グロブでのパッケージ名の省略

型グロブでは、メインパッケージの場合、パッケージ名の省略が可能

```
% perl -le '*h = { 10, 11} ; print *h->{10};' -Mstrict -Mwarnings
11
```

<br>

## 定義済みの変数への適用


上記の機能は、当然、 ***定義済みの変数(配列・連想配列)への代入にも使える。***

1. Perl の[定義済みの変数](https://perldoc.jp/docs/perl/5.6.1/perlvar.pod)は、main パッケージのパッケージ変数である
2. `$\d+`, `@\d+`, `%\d+` は定義済みのリストには載っていないものの、実質定義済みの変数として扱われる


従って 1. については以下の様にコードが書ける。

*%ENV に値を追加したり*

```
% perl -le '"ENV"->{TEST} = "test"; print Dumper \%ENV;' -MData::Dumper
$VAR1 = {
        (前略)
        'TEST' => 'test',
        (後略)
    };
```

*$ARGV[0] を変更したり*

```
% cat test.txt
hoge
% perl -lpe 'BEGIN{ "ARGV"->[0] = "test.txt" }'
hoge
```

<br>

で、2.。

perl では変数名として、シジルの直後に数字のみで構成された文字列が使用可能である。[^3]

[^3]:`perldoc perldata` の変数名の項の下部参照。ちなみにスカラについては、`$0` が `perldoc perlvar` に記載の定義済み変数、記載はないものの `$1` からの 0 埋めされていない数値は、正規表現マッチ結果の入った変数として使われる。それ以外 - 0 が先頭のもの(`$010`) など -  は使われていない。

定義済みとして扱われているので、当然変数名宣言無しでも `use strict; use warnings;` が通る。

```
% perl -le '@0 = (100); print $0[0];'
```

と言うことで、型グロブで記載すると 

```
# perl -le '*0 = [ 100 ]; print *0->[0];'
% perl -le '*0->[0] = 100; print *0->[0];'
100
```

で、`*` を省略


```
% perl -le '0->[0] = 100; print 0->[0];'
100
```

`"0"->[0]` じゃなくて `0->[0]` で機能するのは、Perl のご都合主義の成せる技。(まあ、単に数値だから。)


```
% perl -MDevel::Peek -e '0->[0] = 100; Dump(@0);'
SV = PVAV(0x12500d2f0) at 0x1250173a8
  REFCNT = 1
  FLAGS = ()
  ARRAY = 0x124e0b3e0
  FILL = 0
  MAX = 3
  FLAGS = (REAL)
  Elt No. 0
  SV = IV(0x12500bc00) at 0x12500bc10
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 100                          # <= Integer 100 が入ってますよ
```

<br>


改めて調べようとすると[^4]、Google 先生はボケちゃってるし、(無料版) ChatGPT 先生は頓珍漢な答えしかしてくれないし、質問サイトにも Perl 古参の方々は居なさそうだし、有用なサイトは沈んでるか消えてるし[^5]、 寂しいものだ。

[^4]: 自分自身も型グロブが思い当たらず、ずいぶん遠まわりしてしまった。ここまで、ボケるものか

[^5]: KENT WEB が生き残ってるのに驚愕した！ Copyright が 2023 だから、少なくとも去年まではメンテされているの？

<br>

## BTW

あ、`B::Deparse` の穴みっけ

```
% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;'
10
100
```

↓

```
% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;' -MO=Deparse
BEGIN { $/ = "\n"; $\ = "\n"; }
$0[0] = 100;
package HOGE;
$0[0] = 10;
print $0[0];
print $0[0];
'???';
-e syntax OK
```
↓

```
% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;' -MO=Deparse | grep -v '???' | perl
-e syntax OK
10
10
```

<br>

つか、定義済み変数の"暗黙の main パッケージ変数である"って挙動に対応していないのかな、、、でもないね。

```
% perl -le '"ENV"->{"T"} = "test" ; package HOGE; "HOGE::ENV"->{"T"} = "HOGE"; print "HOGE::ENV"->{"T"}; print "ENV"->{"T"}; 1;'  -MO=Deparse
BEGIN { $/ = "\n"; $\ = "\n"; }
$ENV{'T'} = 'test';
package HOGE;
$HOGE::ENV{'T'} = 'HOGE';
print $HOGE::ENV{'T'};
print $ENV{'T'};
'???';
-e syntax OK
```

<br>