【実務・中級編】INITIAL属性による変数初期化のタイミング – PL/Iの基本構文とデータ制御実践ガイド

【PL/I深掘り】初期化の罠に堕ちるな――INITIAL属性の「静的」と「自動」を使い分ける技術

こんにちは。メインフレームの深淵を覗き続けて幾星霜、今日も今日とてJCLの海を泳ぎ、VSAMの不整合と格闘する皆さんに、PL/Iの「初期化」という地味ながらも極めて重要な技術テーマを語ろうと思う。

若手の頃、私は「INITIAL属性なんて、ただ値を代入するだけだろ?」と高を括っていた。だが、大規模なバッチ改修で、前任者が残した謎のバグを追ううちに、INITIAL属性がコンパイラによってどう扱われるかを知らなければ、基幹システムは守れないと痛感したんだ。

今回は、PROCEDUREにおける変数初期化の真実について、現場の視点から解説する。

1. 静的(STATIC)か、自動(AUTOMATIC)か:それが問題だ

PL/Iにおいて、変数の宣言時に`INITIAL`属性をつけることは多い。だが、その変数が「いつ」初期化されるかを意識しているだろうか?

  • STATIC(静的)変数: プログラムのロード時(実行開始時)に一度だけ初期化される。
  • AUTOMATIC(自動)変数: `PROCEDURE`が呼び出されるたび(または`BEGIN`ブロックに入るたび)に、スタック上にメモリが確保され、その都度初期化が行われる。

ここを混同すると、バッチ処理のループ内で「前回の計算値が残っていて計算結果が狂う」という、現場で最も恥ずかしく、かつ原因究明に時間の掛かるデバッグに追い込まれることになる。

実践的なコード例

まずは、正しく使い分けた典型的なソースを見てほしい。

1
/ —————————————————————– /
/ サンプル:STATICとAUTOMATICの挙動の違いを示すプログラム /
/ —————————————————————– /
TEST_INIT: PROCEDURE OPTIONS(MAIN);

/ STATICはロード時に一度だけ初期化される。カウンター等に有効 /
DCL EXEC_COUNT FIXED BIN(15) STATIC INITIAL(0);

/ AUTOMATICは呼び出しごとに初期化される(デフォルト属性) /
DCL WORK_BUF CHAR(10) AUTOMATIC INITIAL(‘ ‘);

/ プログラムのロジック開始 /
EXEC_COUNT = EXEC_COUNT + 1;

/ VSAMの読み込みや計算処理を模した疑似処理 /
CALL SUB_PROCESS(WORK_BUF);

RETURN;
END TEST_INIT;

SUB_PROCESS: PROCEDURE(P_BUF);
DCL P_BUF CHAR(10) PARM;
/ この中の自動変数は呼び出しごとにクリーンな状態で始まる /
DCL TEMP_VAL FIXED BIN(31) INITIAL(0);

TEMP_VAL = TEMP_VAL + 1;
/ … 業務ロジック … /
END SUB_PROCESS;

2. 実務の現場における「罠」とONユニットへの配慮

メインフレームのバッチでは、入出力エラーや計算例外(ZeroDivideなど)を`ON`ユニットで補足するのが定石だ。ここで注意してほしいのは、`ON`ユニット内で使用する変数の初期化だ。

`ON`ユニットは、意図しないタイミングで制御が飛んでくる。もしその中で`AUTOMATIC`変数を多用し、複雑な初期化を行っていると、コンパイラの最適化やスタックの状態によっては、予期せぬゴミデータに触れるリスクがある。

また、`ALLOCATE`文で動的にメモリを確保する`CONTROLLED`属性の変数の場合、`INITIAL`属性は`ALLOCATE`が実行されるたびに評価される。これを理解していないと、再帰処理の中でメモリリークや初期化漏れを引き起こす原因になる。

デバッグのコツ:BUILTIN関数を活用せよ

変数の状態をトレースする際、泥臭いダンプ出力に頼る前に、以下のような`BUILTIN`関数を活用して、論理的な整合性を確認する癖をつけておこう。

1
/ 変数の属性や状態を確認する際の実践コード例 /
IF ADDR(MY_DATA) = NULL() THEN DO;
/ 割り当てられていない場合は初期化を強制するなどの制御 /
ALLOCATE MY_DATA;
END;

3. ベテランからの提言:シンプル・イズ・ベスト

最後に、現場で数々の改修を乗り越えてきた私からのアドバイスだ。

1. 基本はAUTOMATICで: 明示的に`STATIC`が必要な場合(カウンターや定数テーブルなど)以外は、`AUTOMATIC`(デフォルト)に任せるのが安全だ。変数の有効範囲を最小限に留めることが、バグを生まない鉄則である。
2. INITIALの過信は禁物: `INITIAL`属性は、あくまで「その変数が初めて参照される(あるいはスコープに入る)時点」の期待値に過ぎない。特にVSAMのレコードエリアなどは、必ずプログラム内で明示的に`’ ‘`(スペース)や`0`で初期化するコードを通すこと。
3. コンパイラの最適化を信じすぎない: 最新のコンパイラは優秀だが、古いソースコードを現代のオプションでコンパイルする際は、初期値の扱いが微妙に変わることもある。必ずコンパイルリストの「Attribute Table」を確認する習慣をつけてほしい。

PL/Iは、その言語仕様の広大さゆえに、一生かけても全ての挙動を極めるのは難しいかもしれない。だが、こうした「変数のライフサイクル」という足元を固めるだけで、システム全体の安定性は劇的に向上する。

次回の改修では、コードを書く前に一度だけ立ち止まって考えてみてほしい。「この変数は、本当に今のタイミングで初期化されているべきなのか?」と。その問いこそが、君を一人前のメインフレームアーキテクトに育て上げるはずだ。

では、また現場で会おう。健闘を祈る。

タイトルとURLをコピーしました