PL/IのINITIAL属性、その「甘い罠」を解き明かす――再初期化の真実
現場の諸君、今日もメインフレームの保守お疲れ様。
大規模バッチの改修やマイグレーション調査をしていると、時折「なぜこの変数の値が期待通りにリセットされないんだ?」という不可解なバグに遭遇しないか?
特にPL/Iの`INITIAL`属性は、一見するとただの「変数の初期値設定」に見えるが、その裏にはプロシージャのライフサイクルとメモリ管理という、かなり深遠な設計意図が隠されている。今日は、この初期化のタイミングと挙動について、現場の知見を交えて徹底的に解説しよう。
—
INITIAL属性の「定義」と「実行」の境界線
まず基本を押さえよう。`DCL X FIXED BIN(31) INITIAL(0);` と書いたとき、この `0` が代入されるのはいつか?
結論から言えば、その変数が存在するブロック(PROCEDURE)が「アクティブになった瞬間」だ。
ここで注意が必要なのは、PL/Iにおいて「自動変数(AUTOMATIC)」と「静的変数(STATIC)」で挙動が全く異なる点だ。
- AUTOMATIC(デフォルト): ブロックに入るたびに初期化される。つまり、再帰呼び出しや、繰り返し呼ばれるサブプロシージャ内では、毎回 `INITIAL` 値でリセットされる。
- STATIC: プログラムロード時に一度だけ初期化される。その後、そのプロシージャを何度呼び出しても、前回の値が保持されたままになる。
この違いを理解していないと、集計バッチなどで「前回実行時の累積値が残っている」といった悲劇的なデバッグ案件に追われることになるぞ。
—
実践的コード:VSAM処理における初期化制御
では、実際のバッチ処理を想定したコードを見てみよう。レコード処理におけるカウンタ変数の制御を例にする。
1
MAIN_PROC: PROC OPTIONS(MAIN);
/ VSAMファイルを想定したファイル宣言 /
DCL IN_FILE FILE RECORD INPUT ENV(VSAM);
DCL EOF_FLAG BIT(1) STATIC INIT(‘0’B);
/ STATICにすると、もしこのMAIN_PROCを何らかの理由で再呼び出ししても値が残る /
/ 処理用カウンタ(自動変数) /
DCL REC_COUNT FIXED BIN(31) INIT(0);
ON ENDFILE(IN_FILE) EOF_FLAG = ‘1’B;
OPEN FILE(IN_FILE);
DO WHILE(^EOF_FLAG);
READ FILE(IN_FILE) INTO(DATA_AREA);
IF ^EOF_FLAG THEN DO;
REC_COUNT = REC_COUNT + 1;
/ 何らかのVSAM処理ロジック /
END;
END;
PUT SKIP LIST(‘処理件数:’ || TRIM(CHAR(REC_COUNT)));
CLOSE FILE(IN_FILE);
END MAIN_PROC;
ここで注目すべきポイント
1. EOF_FLAGのSTATIC指定: もしこれを `AUTOMATIC` にして、サブルーチン内で `ENDFILE` を制御しようとすると、ループのたびに値がリセットされるという致命的なミスが起きる。
2. REC_COUNTの再初期化: `MAIN_PROC` が一度の実行で完結するバッチなら問題ないが、もしこれが巨大なメインプログラムから `CALL` されるサブプロシージャだった場合、呼び出されるたびに `REC_COUNT` は `0` に戻る。これが仕様通りなら良いが、もし「累計」をとりたいなら、この変数は `STATIC` または `EXTERNAL` に変更しなければならない。
—
デバッグとトラブルシューティングの極意
現場で「値がおかしい」という報告を受けたとき、俺はまず以下の順で調査する。
1. STORAGE属性の確認: 該当変数が `STATIC` か `AUTOMATIC` かを確認する。特に、古いシステムからの改修では、意図せず `STATIC` が付与されているケースがある。
2. 再帰呼び出しの有無: PL/Iは再帰呼び出しが可能な言語だ。再帰が発生している場合、`AUTOMATIC` 変数はスタック上に生成されるため、呼び出しごとに完全に独立した初期化が行われる。これを「初期化が効いていない」と勘違いするケースが非常に多い。
3. BUILTIN関数の活用: 変数の状態が怪しいときは、`ADDR()` や `STORAGE()` 組み込み関数を使って、メモリ上のどの領域に配置されているかを確認する術を持っておくこと。
—
最後に:アーキテクトからの助言
「変数を宣言したら `INITIAL` でゼロクリアしておく」という習慣は、バグを防ぐ素晴らしいプラクティスだ。しかし、PL/Iにおける `INITIAL` は単なる「初期化」ではなく、「メモリの生存期間に対する宣言」であることを忘れてはならない。
特に、オンラインからバッチまでを網羅するような巨大なシステムを触るとき、この知識の有無が、改修後に発生する「再現性のないバグ」を撲滅する鍵になる。
もし、ある変数が「ある時はリセットされ、ある時は残っている」という現象に突き当たったら、まずその変数の宣言を疑え。コンパイラの挙動を責める前に、我々プログラマがその変数の「寿命」を正しく設計できているかを振り返ることだ。
明日からの保守作業、この視点を持ってコードを眺めてみてくれ。きっと今まで見えなかった「変数の物語」が見えてくるはずだ。健闘を祈る。
