導入
メインフレーム開発において、PL/Iの引数渡しは「参照渡し(Pass-by-Reference)」が標準です。これはデータのメモリ上のアドレスを直接渡す仕組みであり、大規模な構造体や配列をコピーすることなく高速に処理できるメリットがあります。しかし、呼び出し先のサブプログラムで値を変更すると、呼び出し元の変数まで即座に書き換わってしまうため、この特性を正しく理解していないと、デバッグ困難な「意図しない副作用」を生む原因となります。本稿では、参照渡しの仕組みと、他言語(Java等)へ移行する際に注意すべき設計上のポイントを解説します。
基礎知識
「参照渡し」とは、変数の値を複製して渡す「値渡し」とは異なり、変数が格納されているメモリの開始アドレスを渡す方式です。PL/Iでは、呼び出し側で指定した変数のアドレスがそのままサブプログラムの引数として渡されます。
メリット: メモリ領域のコピーが発生しないため、巨大な構造体や配列を引数にしてもCPU負荷が非常に低く、処理速度が高速です。
リスク: サブプログラム内での代入操作が、呼び出し元の変数を直接書き換えることを意味します。意図せず値を更新してしまうと、後続の処理に致命的な影響を与えます。
実装/解決策
参照渡しによる副作用を避けるための設計指針は、サブプログラムの役割を明確にすることです。
1. 読み取り専用として扱う: 値を変更する必要がない場合は、サブプログラム内で計算用の一時変数(ローカル変数)を定義し、そこに値をコピーしてから操作します。
2. 意図的な更新を明示する: 値を更新することが目的のルーチン(Setter的な役割)であれば、引数名に「_OUT」などを付与し、呼び出し元に更新される可能性があることをコード上で示唆します。
サンプルプログラム
以下の例は、PL/Iにおける参照渡しの挙動を示すサンプルです。
/ 呼び出し元のメインプログラム /
TEST_PROG: PROC OPTIONS(MAIN);
DCL MY_VAL FIXED BIN(31) INIT(100);
/ サブプログラムへ変数のアドレスを渡す /
CALL MODIFY_VAL(MY_VAL);
/ 呼び出し元のMY_VALも書き換わっている /
PUT SKIP LIST(‘更新後の値:’, MY_VAL);
END TEST_PROG;
/ サブプログラム /
MODIFY_VAL: PROC(P_VAL);
DCL P_VAL FIXED BIN(31); / 参照渡しで受け取る /
/ ここで書き換えると呼び出し元の値も変わる /
P_VAL = P_VAL + 50;
END MODIFY_VAL;
応用・注意点
現代のオブジェクト指向言語(Javaなど)へ移行する際、最も注意すべきは「数値型(FIXED BIN等)の扱い」です。
Javaではint型などのプリミティブ型は「値渡し」ですが、PL/Iでは数値型もすべて「参照渡し」として扱われます。そのため、PL/IからJavaへコードを移植する際は、単にメソッドを呼び出すだけでは値が更新されません。
回避策:
1. 更新が必要な値は、メソッドの「戻り値」として返す設計に変更する。
2. もしくは、Java側でAtomicIntegerや自作のラッパークラスを使用して、値を変更可能なオブジェクトとして保持する設計へ変更する必要があります。
メインフレームからオープン系への移行プロジェクトでは、この「参照渡し」の差分が致命的なバグの温床となるため、移行設計の初期段階で入出力パラメータの仕様を厳格に定義してください。

コメント