メソッドのオーバーロード: JVM COBOL

オーバーロードについて

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

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

メソッドのオーバーロード: JVM COBOL

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

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

COBOL (またはその他の言語) で記述されたコードでクラスやインターフェイスのメソッドが呼び出される際に、その名前のメソッドが複数存在する場合は、利用可能なメソッドが選択されます。この選択は、パラメーターの数、およびパラメーターの型の「最適な」一致に基づいて行われます。適切なシグネチャのメソッドが見つからない場合、「method not found」(メソッドが見つからない) エラーが生じます。この名前が付いた他のすべてのメソッドよりも適切な一致を提供するメソッドがない場合、「ambiguous match」(曖昧な一致) エラーが表示されます。

RETURNING 項目の型はメソッドのシグネチャの一部ですが、呼び出されるメソッドが RETURNING 型に基づいて選択されることはありません。これは .NET および JVM との相違点であり、.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 など) - com.microfocus.cobol.program.ScaledInteger (JVM COBOL)
暗黙の小数点のない符号なし数値項目: .NET COBOL:
  • 3 桁未満 - 符号なし int8
  • 5 桁未満 - 符号なし int16
  • 10 桁未満 - 符号なし int32
  • 19 桁未満 - 符号なし int64

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

暗黙の小数点のない符号付き数値項目:
  • 3 桁未満 - int8
  • 5 桁未満 - int16
  • 10 桁未満 - int32
  • 19 桁未満 - int64
他のすべての型の PIC X、グループなど 文字列

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

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

JVM 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 で定義され、op_Implicit という名前のメソッドが結果として作成されます。