サブプロシージャーを多重定義する
RPGでサブプロシージャーを多重定義する機能は、以前からずっと待ち望んでいたものでした。IBMは、テクノロジー リフレッシュ(7.4のTR1または7.3のTR7)を通じて、ようやくその機能を利用可能にしました。その用語にあまり馴染みがない方に向けて簡単に説明するとすれば、RPGにおける多重定義(overloading)は、同じ名前の複数のサブプロシージャーを異なる実装で作成する機能です。
それでは、プログラムおよびサブプロシージャーを書くことに関して、多重定義がどのようにメリットをもたらすかについて見て行きましょう。以下に示すのは、あるプロトタイプ コピー メンバーの一部であり、以下の3つのサブプロシージャーのプロトタイプの部分のみを抜き出したものです。
dcl-pr format_from_Date varChar(10) extProc(*dclCase);
dateIn date(*ISO) const;
end-pr;
dcl-pr format_from_Number varChar(10) extProc(*dclCase);
dateIn zoned(8) const;
end-pr;
dcl-pr format_from_Character varChar(10) extProc(*dclCase);
dateIn char(10) const;
end-pr;
これら3つのサブプロシージャーは、すべて同じことを行います。すなわち、MDYフォーマットで日付の文字表現を返します。これら3つのサブプロシージャーの違いは、渡されるパラメーターです。1つは日付、1つは日付を表す数値、1つは日付を表す文字です。
このことが意味するのは、日付フォーマットの取得が必要になったときには、日付を格納しているフィールドのデータ タイプに応じてどのサブプロシージャーを呼び出すべきか分かっている必要があるということです。
dcl-s forDate date(*ISO) inz(D'2020-08-01');
dcl-s forNum zoned(8) inz(20200801);
dcl-s forChar char(10) inz('2020-08-01');
dcl-s returnDate char(10);
returnDate = format_from_Date(forDate);
returnDate = format_from_Number(forNum);
returnDate = format_from_Character(forChar);
多重定義することにより、すでに定義した3つのプロトタイプを結合する共通のプロトタイプを定義することができます。
dcl-pr format_from_Date varChar(10) extProc(*dclCase);
dateIn date(*ISO) const;
end-pr;
dcl-pr format_from_Number varChar(10) extProc(*dclCase);
dateIn zoned(8) const;
end-pr;
dcl-pr format_from_Character varChar(10) extProc(*dclCase);
dateIn char(10) const;
end-pr;
dcl-pr format_Date varChar(10) overLoad( format_from_Date
: format_from_Number
: format_from_Character);
このことが意味するのは、プログラム/サブプロシージャーの呼び出しで、パラメーターに関係なく、3つすべてのサブプロシージャーの呼び出しに同じ名前を使用できるようになったということです。
dcl-s forDate date(*ISO) inz(D'2020-08-01');
dcl-s forNum zoned(8) inz(20200801);
dcl-s forChar char(10) inz('2020-08-01');
dcl-s returnDate char(10);
returnDate = format_Date(forDate);
returnDate = format_Date(forNum);
returnDate = format_Date(forChar);
この結合されたコードに新たなサブプロシージャーを追加してみましょう。このサブプロシージャーも日付の文字表現を返しますが、返される日付フォーマットの指定を可能にする追加のパラメーターがあります。
dcl-pr format_from_Date_With_Format varChar(10) extProc(*dclCase);
dateIn date(*ISO) const;
toFormat char(4) const;
end-pr;
この新たなプロシージャーには余分なパラメーターがありますが、それでもoverloadのリストに追加することができます。
dcl-pr format_Date varChar(10) overLoad( format_from_Date
: format_from_Number
: format_from_Character
: format_from_Date_With_Format);
ということは、新たなサブプロシージャーに既存の(共通の)名前を使用できるということです。
dcl-s forDate date(*ISO) inz(D'2020-08-01');
dcl-s forNum zoned(8) inz(20200801);
dcl-s forChar char(10) inz('2020-08-01');
dcl-s returnDate char(10);
returnDate = format_Date(forDate);
returnDate = format_Date(forNum);
returnDate = format_Date(forChar);
returnDate = format_Date(forDate: '*MDY');
素晴らしくないでしょうか。
規則
以下に、OVERLOADキーワードを使用してプロトタイプを定義するときに遵守する必要がある規則を示します。
- 用語: OVERLOADキーワードを使用しているプロトタイプを、多重定義されたプロトタイプと呼びます。OVERLOADキーワードでリストされているサブプロシージャーを、候補プロトタイプと呼びます。
- OVERLOADキーワードを使用しているプロトタイプでパラメーターを指定することはできません。
- OVERLOADキーワードを使用しているプロトタイプは、END-PRで終わりません。
- すべての候補プロトタイプの戻り値タイプは、多重定義されたプロトタイプと同じ戻り値タイプ(または戻り値なし)でなければなりません。
- 多重定義されたプロトタイプで使用できる他のキーワードは、戻り値のデータ タイプと関連するものだけです。
- 候補プロトタイプは、どのようなタイプのプロトタイプであってもかまいません。それらは、プログラム、プロシージャー、およびJavaのメソッドのプロトタイプであってもかまいません。
厳格なコンパイラー
パラメーターのチェックに関しては、コンパイラーは極めて厳格です。すべての候補プロトタイプは、真に一意でなければなりません。たとえば、コンパイラーは以下のoverloadプロシージャーを許容しません。パラメーターの定義が異なっていても、CONSTキーワードを使用することは、いずれかのサブプロシージャーを呼び出すことができることを意味します。
dcl-pr oneParm varChar(10) extProc(*dclcase);
parm_1 char(1) const;
end-Pr;
dcl-pr twoParm varChar(10) extProc(*dclcase);
parm_1 char(10) const;
end-Pr;
dcl-pr formatParm varChar(10) overload(twoParm: oneParm);
コンパイラー リスト
コンパイラー リストには、リストの最後にOverloaded Prototypesセクションが含まれるようになりました。このセクションに示される情報量は、/OVERLOAD DETAILまたは/OVERLOAD NODETAILコンパイラー ディレクティブを使用して制御することができます。デフォルトは、/OVERLOAD NODETAILです。/OVERLOADコンパイラー ディレクティブは、ソース メンバーで、複数回、指定することができます。
以下は、/OVERLOAD DETAILが指定された場合のOverloaded Prototypesセクションの例です。
O V E R L O A D E D P R O T O T Y P E S
CALLS TO PROTOTYPES FOR FORMATPARM
CALLED PROTOTYPE REFERENCES (D=DETAILS BELOW)
TWOPARM 48D
ONEPARM
DETAILED DETERMINATION FOR CALLS TO FORMATPARM
CALL AT STATEMENT 48 COLUMN 14
SELECTED PROTOTYPE: TWOPARM
CALLS TO PROTOTYPES FOR FORMAT_DATE
CALLED PROTOTYPE REFERENCES (D=DETAILS BELOW)
FORMAT_FROM_DATE...
FORMAT_FROM_NUMBER...
45D
FORMAT_FROM_CHARACTER...
46D
DETAILED DETERMINATION FOR CALLS TO FORMAT_DATE
CALL AT STATEMENT 45 COLUMN 14
ERROR MESSAGES ISSUED FOR PARAMETER 1 FOR FORMAT_FROM_DATE
*RNF7536 30 45 004500 The type of parameter 1 specified for the call does not
match the prototype.
ERROR MESSAGES ISSUED FOR PARAMETER 1 FOR FORMAT_FROM_CHARACTER
*RNF7536 30 45 004500 The type of parameter 1 specified for the call does not
match the prototype.
SELECTED PROTOTYPE: FORMAT_FROM_NUMBER
CALL AT STATEMENT 46 COLUMN 14
ERROR MESSAGES ISSUED FOR PARAMETER 1 FOR FORMAT_FROM_DATE
*RNF7536 30 46 004600 The type of parameter 1 specified for the call does not
match the prototype.
ERROR MESSAGES ISSUED FOR PARAMETER 1 FOR FORMAT_FROM_NUMBER
*RNF7536 30 46 004600 The type of parameter 1 specified for the call does not
match the prototype.
SELECTED PROTOTYPE: FORMAT_FROM_CHARACTER
* * * * * E N D O F O V E R L O A D E D P R O T O T Y P E S * * * * *
以下は、/OVERLOAD NODETAILが指定された場合の例です。
O V E R L O A D E D P R O T O T Y P E S
CALLS TO PROTOTYPES FOR FORMATPARM
CALLED PROTOTYPE REFERENCES (D=DETAILS BELOW)
TWOPARM 48
ONEPARM
CALLS TO PROTOTYPES FOR FORMAT_DATE
CALLED PROTOTYPE REFERENCES (D=DETAILS BELOW)
FORMAT_FROM_DATE...
FORMAT_FROM_NUMBER...
45
FORMAT_FROM_CHARACTER...
46
* * * * * E N D O F O V E R L O A D E D P R O T O T Y P E S * * * * *
/OVERLOADコンパイラー ディレクティブは、ソース メンバーで、複数回、指定することにより、サブプロシージャーの呼び出しごとに表示される詳細の量を指定することができます。
サブプロシージャーを多重定義することによって、サブプロシージャーを少し使いやすくすることができます。きっと、皆さんも、それらの利用法を見つけられることと思います。