PL/Iの「RECURSIVE」と仲良くなる:再帰呼び出しでスタックを爆発させないための心得
こんにちは。メインフレームの世界へようこそ。
COBOLの「手続き型」やJavaの「オブジェクト指向」に慣れ親しんできた方にとって、PL/Iは少し不思議で、どこか懐かしい「万能選手」のように見えるはずです。今日は、PL/Iにおける再帰呼び出し(RECURSIVE)という、少し刺激的な機能についてお話しします。
「再帰」と聞くと、なんだか複雑で怖いイメージを持つ方も多いですよね。でも大丈夫。PL/Iの流儀さえ分かってしまえば、まるで自分の分身を次々と送り出してタスクをこなすような、非常にエレガントな処理が書けるようになりますよ。
—
なぜPL/Iには「RECURSIVE」が必要なのか?
多くの言語では、関数はデフォルトで再帰呼び出しが可能ですが、PL/Iは少し慎重です。PL/Iにおいて、あるプロシージャ(PROCEDURE)が自分自身を呼び出すためには、明示的に `RECURSIVE` 属性を宣言する必要があります。
1
/ 再帰処理を行うプロシージャの宣言例 /
FACTORIAL: PROCEDURE(N) RECURSIVE;
DCL N FIXED BIN(31);
DCL RESULT FIXED BIN(31);
IF N <= 1 THEN RETURN(1); ELSE DO; / 自分自身を呼び出す! / RESULT = N FACTORIAL(N - 1); RETURN(RESULT); END; END FACTORIAL; なぜわざわざキーワードを付けるのか? それは、メインフレームの貴重なリソース(ストレージ)を無駄に食いつぶさないための「ブレーキ」だからです。
—
ストレージ管理のリアル:スタックオーバーフローとの戦い
再帰処理で最も注意しなければならないのが「スタックオーバーフロー」です。これは、再帰が深く潜りすぎて、プログラムに割り当てられたメモリ領域(スタック)が溢れてしまう現象です。
Javaなら例外が飛んで終わりかもしれませんが、メインフレームの世界では、「システム全体が異常終了(ABEND)」という、よりシビアな結果を招くことがあります。
ここで「AUTOMATIC」属性の罠を理解しましょう
PL/Iでは、プロシージャ内で宣言する変数は、デフォルトで `AUTOMATIC`(自動)ストレージとなります。これは、「そのプロシージャが呼び出されるたびに、スタック領域に新しい変数の場所が作られる」ことを意味します。
再帰が1,000回回れば、1,000個分の変数がスタックに積み上がります。もし、再帰の深いところで巨大な配列を宣言していたら……想像するだけで恐ろしいですよね。
安全に再帰させるための3つの鉄則
1. 「終了条件」を死守する: どんなに美しいアルゴリズムでも、停止しない再帰はただの爆弾です。終了条件(Base Case)は、必ず最初にチェックするようにしましょう。
2. 巨大な変数は外に出す: 再帰プロシージャの中で、`DCL BIG_ARRAY(10000) FIXED BIN;` のような大きな変数を宣言してはいけません。大きなデータが必要なら、`STATIC`(静的)属性にするか、呼び出し元のプロシージャからポインタで渡す工夫をしましょう。
3. 呼び出し回数の上限を意識する: 業務ロジックとして「何階層まで潜る可能性があるか」を常に計算しておきましょう。メインフレームのスタックサイズには物理的な限界があります。
—
実務で役立つ「スタックを守る」コードのヒント
実務で再帰を書く際、以下のような構造にすると、不意の爆発を防ぎやすくなります。
1
/ メインの入り口 /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);
DCL COUNT FIXED BIN(31) INIT(5);
/ 深い階層の再帰を呼び出す前には必ず確認 /
CALL SAFE_RECURSION(COUNT);
END MAIN_PROC;
/ 再帰用プロシージャ /
SAFE_RECURSION: PROCEDURE(N) RECURSIVE;
DCL N FIXED BIN(31);
/ 1. 安全装置:再帰回数が多すぎないかチェック /
IF N > 100 THEN DO;
PUT SKIP LIST(‘警告: 深すぎる再帰呼び出しを検知しました’);
RETURN;
END;
/ 2. 処理本体 /
IF N > 0 THEN CALL SAFE_RECURSION(N – 1);
END SAFE_RECURSION;
—
最後に:怖がる必要はありません
PL/Iの `RECURSIVE` は、正しく使えば非常に強力な武器になります。COBOLで苦労していた複雑なツリー構造の探索も、PL/Iなら数行の再帰処理でスマートに書けてしまうことも少なくありません。
「スタックを汚さない(巨大な変数を再帰に入れない)」ことさえ意識すれば、PL/Iはあなたの忠実な相棒として、長年動き続ける基幹システムの重責を担ってくれるはずです。
もし現場で「再帰を使いたいけれど、メモリが心配だ」という場面に遭遇したら、まずは変数の属性を `AUTOMATIC` から `STATIC` に変えられないか、あるいは再帰の深さを制限できないか、一つずつ紐解いてみてください。
メインフレームの旅路は、まだまだ奥が深いです。また何かあれば、いつでも相談してくださいね。

コメント