マネージ COBOL でのメソッドのオーバーロード

オーバーロードについて

オーバーロードは、複数の実装でメソッド名をオーバーロードするプログラミング技術です。

たとえば、CalculateBill というメソッドがあり、購入品のリストをパラメーターとして取るとします。また、このメソッドの変化形を使用できます。この変化形には、購入品のリストの他に割引コードを表す別のパラメーターがあります。2 つのメソッドでは同じ名前を使用できます。メソッドを呼び出すと、割引コードのパラメーターの有無に基づき必要なメソッドが選択されます。

マネージ COBOL でのメソッドのオーバーロード

マネージ COBOL では、指定のクラスやインターフェイスが同じ名前のメソッドを複数使用することが許可されており (非常に一般的な方法)、署名を別にすることでそれぞれが区別されます。メソッドの署名は、次の内容で決まります。

  • パラメーターの数
  • 各パラメーターのタイプ
  • 各パラメーターの引き渡しモード (BY VALUE、BY REFERENCE、または BY OUTPUT)
  • 戻りタイプ

COBOL または他の言語で記述されるコードが一部のクラスやインターフェイスでメソッドを呼び出す際に特定の名前のメソッドが複数存在する場合、利用可能なメソッドが選択されます。選択は、パラメーターの数と、パラメーターに「最適な」タイプの一致に基づきます (「最適な」の正確な定義は複雑であるため、後ほど説明します)。適切な署名のメソッドが見つからない場合、method not found (メソッドが見つからない) エラーが生じます。この名前が付いた他のすべてのメソッドよりも適切な一致を提供するメソッドがない場合、ambiguous match (曖昧な一致) エラーが表示されます。

RETURNING 項目のタイプがメソッドの署名の一部である場合、呼び出されるメソッドの選択は、決して RETURNING タイプには基づきません。これは .NET と JVM で異なるため、クラスでは、RETURNING タイプだけが異なるメソッドを複数使用できます。これは、一般的に適切な方法ではありません。単一クラス内でこのようなメソッドが複数見つかった場合、COBOL でエラーが生成されます。このような複数のメソッドが COBOL プログラムで生じるのは、明示的な演算子と暗黙的な演算子の場合のみです。

メソッドの署名

COBOL パラメーターのタイプは、次の方法で指定できます。

  • AS 構文を使用して、タイプを PROCEDURE DIVISION 句で明示的に参照する
  • 連絡節項目を指定のタイプで宣言し、その連絡節項目を PROCEDURE DIVISION USING 句で参照する

参照パラメーターおよび出力パラメーターの場合、マネージ タイプは、相当するマネージ タイプへのマネージ ポインターとして直接公開されます。マネージ タイプに相当しない COBOL データ タイプ (PIC X フィールド、グループ、BINARY-LONG 以外の数値フィールドなど) は、COBOL ポインターとして公開されます。

値パラメーターと RETURNING 項目の場合、タイプは次のように公開されます。

COBOL タイプ: 公開される形態:
マネージ タイプ 対応するタイプのオブジェクト
19 を超える小数桁位置の数値項目 MicroFocus.COBOL.Program.BigDecimal
暗黙の小数点の数値項目、PIC 9(9)v99 など、すべてのサイズ - JVM COBOL の com.microfocus.COBOL.program.ScaledInteger
暗黙の小数点のない符号なし数値項目: .NET COBOL:
  • 3 よりも少ない数字の桁 - 符号なし int8
  • 5 よりも少ない数字の桁 - 符号なし int16
  • 10 よりも少ない数字の桁 - 符号なし int32
  • 19 よりも少ない数字の桁 - 符号なし int64

JVM COBOL では、これらは符号付き数値項目と同様に公開されます。

暗黙の小数点のない符号付き数値項目:
  • 3 よりも少ない数字の桁 - int8
  • 5 よりも少ない数字の桁 - int16
  • 10 よりも少ない数字の桁 - int32
  • 19 よりも少ない数字の桁 - int64
他のすべてのタイプ、PIC X、グループなど string

メソッドのオーバーロードの解決

メソッドのオーバーロードの解決は次の 2 つの段階で行われます。

  1. 適用可能なすべてのメソッドの選択。呼び出し元のプログラムで指定される引数をターゲット メソッドのパラメーターと比較できる特定の名前のメソッドをすべて選択します。こうした適用可能なメソッドが見つからない場合、エラー (メソッドが見つからない) が生成されます。
  2. 適用可能なメソッドのセット内での「最適な」一致の選択。選択プロセスの全体の意図は、特定の引数セットに最適な一致 (最も固有の一致を意味する) を生成することにあります。

    形式的には、適用できるどのメソッドのオーバーロードよりも適切なメソッドのオーバーロードが選択されます。他のどのオーバーロードよりも適切と判断される 1 つのオーバーロードがない場合、一致は曖昧と見なされ、コンパイラでエラーが生じます。

    この 2 フェーズのプロセスで一意の最適な一致が生じない場合、エラー (曖昧な一致エラー) が生成されます。

注:

この説明では、引数という用語は、呼び出しメソッドで指定されるパラメーターのセットになります (例: 次の文におけるobj01 )。

INVOKE Method1(obj01)

パラメーターという用語は、各メソッドの定義 (PROCEDURE DIVISION USING ヘッダー内) で指定される形式的なパラメーターになります。

適用可能なメソッドの選択

まず、ターゲット クラスまたはその親クラスのいずれかに存在する、必要な名前のメソッド一式 (同一署名のメソッドを除く) から開始します。この一式から、メソッドにエンコードされる可視性属性に基づいて、呼び出し元のプログラムで表示できないメソッドは、次のように破棄されます。

属性 可視性
PRIVATE 呼び出しクラスがターゲット クラスと同じ場合のみ表示可能
PUBLIC 常に表示可能
PROTECTED 呼び出しクラスがターゲット クラスから派生する場合のみ表示可能
INTERNAL ターゲット クラスが呼び出しクラスと同じアセンブリ内にある場合のみ表示可能
PROTECTED INTERNAL 呼び出しクラスがターゲット クラスから派生する場合、または呼び出しクラスがターゲットと同じアセンブリ内にある場合のみ表示可能

次に、必要なメソッドがインスタンス メソッド (オブジェクト インスタンスに適用されるメソッド) の場合、すべての静的メソッドが破棄されます。同様に、必要なメソッドが静的メソッドの場合、すべてのインスタンス メソッドが破棄されます。

ここで、各メソッドを順番に調べ、通常の形式で適用できるかどうかを判断します。これは次のように決定されます。

  1. 引数の数がメソッドのパラメーターの数と異なる場合、このメソッドは破棄されます。
  2. ターゲット メソッドのパラメーターのタイプが、参照渡しの汎用 COBOL データの場合、JVM ネイティブ タイプを除くどの引数タイプも一致すると仮定されます。
  3. 明示的なパラメーター引き渡しモード (BY CONTENT、BY VALUE または BY OUTPUT) を使用する各引数の場合、そのモードが、調査対象メソッドのパラメーターの定義に対応する必要があります。
  4. 参照パラメーターまたは出力パラメーターの場合、引数のタイプは、パラメーターのタイプと正確に同じでなければなりません。

    値パラメーターの場合、暗黙変換が、引数のタイプから、対応するパラメーターのタイプに存在する必要があります。このような暗黙変換で切り捨てが必要な場合、このメソッドは切り捨て一致となります。

メソッドがこれらのルールに従って適用できない場合、拡張形式でのメソッドの一致が確認されます。どちらの場合も、次の内容が当てはまります。

  • メソッドの最後のパラメーターは params 属性の配列になります。
  • メソッド パラメーターの総数 (この配列パラメーターを除く) は、引数の数以下になります。

メソッドの拡張形式は、配列パラメーターを、配列要素と同じタイプのゼロ個以上の値パラメーターで置き換えることで通常の形式から派生します。このため、パラメーターの総数は、呼び出し引数の数と同じになります。クラスに同じ拡張署名のメソッドが通常形式ですでに含まれる場合、このメソッドは適用不可と判断されます。それ以外の場合、拡張形式は、上記の通常形式のテストと同様に適用可能かどうかのテストが行われます。

上記の選択手順後:

  1. あるメンバーが適用可能であることが正確に判明した場合、そのメソッドが必要なメソッドであることがわかります。
  2. 複数のメソッドが適用可能であることが判明した場合、最適なメソッドの検出が行われます。
  3. 非切り捨て一致が見つかった場合、すべての切り捨て一致が破棄されます。
  4. 検出された唯一の一致が切り捨て一致で、このような一致が 1 つだけ検出された場合、この一致が選択されたメソッドになり、警告が生成されます。切り捨て一致が複数見つかった場合、コンパイラは次のエラーを戻します。
    ambiguous match
  5. 適用可能なメソッドが見つからない場合、コンパイラは次のエラーを戻します。
    method not found

メソッドのオーバーロードの改善

引数タイプのセット (A1、A2、…An) の引数リスト A があり、2 つの適用可能なメソッドがパラメーター タイプ (P1…Pn) および (Q1、…Qn) の Mp と Mq をオーバーロードするとします。この場合、パラメーターは必要に応じて拡張形式に変換されています (上記参照)。

次に、Mp は Mq よりも適切なメソッドのオーバーロードであると言えます。どちらの場合も次の内容が当てはまります。

  • 各引数について、Ax から Px の暗黙変換は、Ax から Qx の変換よりも無効ではありません (より適切な変換の定義については次を参照)。
  • Ax から Px への変換が Ax から Qx への変換よりも適している引数が 1 つ以上あります。

2 つの変換 (タイプ S からタイプ T1 およびタイプ S から T2) があるとします。T1 と T2 が次のような場合、T1 の方が適切な変換になります。

T1: T2 が次のいずれかの場合:
S と同じ すべて
binary-char
  • binary-char unsigned
  • binary-short unsigned
  • binary-long unsigned
  • binary-double unsigned
binary-short
  • binary-short unsigned
  • binary-long unsigned
  • binary-double unsigned
binary-long
  • binary-long unsigned
  • binary-double unsigned
binary-double
  • binary-double unsigned

それ以外の場合、どちらの変換も適切ではありません。

簡単なメソッドのオーバーロードの例

次の例では、提供される引数がターゲット メソッドの引数と正確に同じではない場合でも、最も固有のルールが実施される方法を示します。

       class-id Class1 static.
       method-id main static.
       01 objAnyObject object.
       01 objString string.
       01 objDateTime type DateTime.         *> .NET COBOL 
      * 01 objDateTime type java.util.Date.  *> JVM COBOL
       01 ref1 type Class1.
       procedure division.
           set ref1 to new Class1
           invoke ref1::method1                *> uses variant 1 
           invoke ref1::method1(objAnyObject)  *> uses variant 2 
           invoke ref1::method1(objString)     *> uses variant 3
           invoke ref1::method1(objDateTime)   *> also uses variant 2, 
               *> because an object of type DateTime can be assigned  
               *> to an Object but not to a String. 
       end method.

       method-id method1.     *> Variant 1 (no parameters)
       procedure division.   
           display "variant 1"
       end method.

       method-id method1.     *> Variant 2 (object parameter)
       procedure division using by value objAnyObject as object.  
           display "variant 2"
       end method.

       method-id method1.     *> Variant 3 (string parameter)
       procedure division using by value objString as string.   
           display "variant 3"
       end method.

       end class.

暗黙変換

暗黙変換は、タイプ T のオブジェクトにタイプ S のオブジェクトを割り当てることができる場合、タイプ S からタイプ T に存在します。次の文に相当します。

SET obj-T TO obj-S

次のタイプの暗黙変換を利用できます。

識別変換

これは、S が T と同じタイプであることを意味します。

暗黙数値変換

COBOL では、通常、数値項目を他の項目に割り当てることができますが、データの損失はユーザーの責任になります。ただし、変換がメソッドのオーバーロードを目的に存在するかどうかを判断する場合、適切な変換と切り捨て変換を区別します。適切な変換とは、固定小数点と浮動小数点との間の変換で精度が失われる可能性はあってもデータの大きさは失われない変換のことです。

マネージ COBOL タイプの場合、適切な暗黙変換は次のようになります。

binary-char
  • binary-short
  • binary-long
  • binary-double
  • float-short
  • float-long
  • decimal
binary-char unsigned

binary-char と同じ、次の内容を追加:

  • binary-short unsigned
  • binary-long unsigned
  • binary-double unsigned
binary-short
  • binary-long
  • binary-double
  • float-short
  • float-long
  • decimal
binary-short unsigned

binary-short と同じ、次の内容を追加:

  • binary-long unsigned
  • binary-double unsigned
binary-long
  • binary-double
  • float-short
  • float-long
  • decimal
binary-long unsigned

binary-long と同じ、次の内容を追加:

  • binary-double unsigned
binary-double
  • float-short
  • float-long
  • decimal
binary-double unsigned

binary-double と同じ

character
  • binary-short unsigned
  • binary-long
  • binary-long unsigned
  • binary-double
  • binary-double unsigned
  • float-short
  • float-long
  • decimal
float-short
  • float-long
暗黙列挙変換

値 0 は、どの列挙タイプにも変換できます。

暗黙参照変換

S と T が参照タイプの場合、次の状況で S を T に割り当てることができます。

  • タイプ S がタイプ T から (直接または間接的に) 派生する場合。たとえば、すべてのタイプがそこから派生するため、T が java.lang.Object となる場合などです。
  • タイプ S がインターフェイス タイプ T を実装する場合
  • S が要素タイプ E1 の配列タイプであり、T が要素タイプ E2 の配列タイプである場合、S は次の状況で T に割り当てることができます。
    • S と T の次元の数が同じ
    • E1 と E2 がどちらも参照タイプ
    • 暗黙変換が E1 から E2 に存在する
  • どの配列タイプも JVM COBOL のタイプ java.util.Array に割り当てることができる場合
  • Null を参照タイプに割り当てることができる場合
ボックス化変換

ボックス化と呼ばれるプロセスで、どの値タイプも java.lang.Object タイプに変換できます。このプロセスの一環で、値はオブジェクト ヒープにコピーされ、参照が作成されます。

暗黙定数式変換

どの数値定数も、その定数のすべての値を含むことができるタイプに変換できます。たとえば、値 1 は、BINARY-CHAR UNSIGNED と BINARY-CHAR のどちらにも変換できます。

ユーザー定義の暗黙変換

ユーザー定義の暗黙変換は、S から S1 へのオプションの暗黙数値変換、結果が T1 になるユーザー定義の暗黙変換演算子の実行、T へのもう 1 つのオプションの暗黙数値変換の順で構成されます。ユーザー定義の暗黙変換演算子は、OPERATOR-ID IMPLICIT を使用して COBOL で定義され、name op_Implicit を含むメソッドが結果として作成されます。