Chapter 3: Method Signatures and Method Overloading in .NET

This chapter describes method signatures and method overloading in .NET.

Method Overloading

In .NET it is permissible (and very common practice) for a given class or interface to have multiple methods with the same name, which are distinguished from each other by having different signatures. The signature of a method is determined by the:

When code written in COBOL, or any other language, attempts to invoke a method in some class or interface, and more than one method with the given name exists, then a choice of the available methods is made. The choice is based on the number of parameters and the ‘best’ type match for the parameters (the precise definition of ‘best’ is complex and is treated later). If no method with a suitable signature can be found, a ‘method not found’ error results. If there is no method that provides a better match than all the other possible methods with this name, an ‘ambiguous match’ error is given.

Although the type of the RETURNING item is a part of the method’s signature, the choice of method to be invoked is never based on the RETURNING type. In fact, although .NET does allow multiple methods to exist in a class, where the methods differ only by returning type, this is not generally good practice, and COBOL will produce an error if it finds such multiple methods within a single class. The only time when such multiple methods can arise from a COBOL program is in the case of the Explicit and Implicit operators. See Operator-ID Paragraph.

Example of Simple Method Overloading

class-id. A.
repository.
     Class sys-datetime as “System.DateTime”.
static.
Method-id. Main.
01 obj-any object.                        *> define an item of type System.Object
01 obj-string string.                     *> define an item of type System.String
01 obj-datetime sys-datetime.             *> define an item of type System.DateTime

    Invoke self::”Method1”                *> invokes variant 1
    Invoke self::”Method1”(obj-any)       *> invokes variant 2
    Invoke self::”Method1”(obj-string)    *> invokes variant 3
    Invoke self::”Method1”(obj-datetime)  *> invokes variant 2
*> Note that the last invoke maps onto variant 2 because an object of type
*> System.DateTime can be assigned to a System.Object but not to a System.String
End method main.
Method-id. Method1.    *> Variant 1 (no parameters)
Procedure division.
…
End method method1.
Method-id. Method1.    *> Variant 2 (object parameter)
Procedure division using by value o1 as object.
…
End method method1.
Method-id. Method1.    *> Variant 3 (string parameter)
Procedure division using by value o1 as string.
…
End method method1.
End static.
End class a.

Method Signatures Defined by COBOL Programs

The type of a COBOL parameter may be specified by:

For REFERENCE and OUTPUT parameters, native .NET types are exposed directly as managed pointers to the corresponding .NET type. COBOL data types that do not correspond to native .NET types (such as PIC X fields, groups, numeric fields other than BINARY-LONG and so on) are exposed as COBOL pointers (objects of type MicroFocus.COBOL.Program.Reference).

For VALUE parameters, and RETURNING items, native .NET types are exposed as objects of the corresponding type.

Other COBOL data types used as VALUE parameters are exposed as follows:

See COBOL Type Compatibility for details of the correspondence between native .NET types and COBOL data types.

Method Overload Resolution

In this discussion, the term arguments means the set of parameters specified in the invoking method (for example obj01 in the statement INVOKE self::”Method1”(obj01)). The term parameters means the formal parameters specified in each method definition (in the PROCEDURE DIVISION USING header).

Method overload resolution takes place in two phases:

  1. Selection of all applicable methods, i.e. selection of all those methods with the given name for which the arguments specified in the invoking program are compatible with the parameters of the target methods. If no such applicable method is found, then an error (method not found) is produced.
  2. Selection of the ‘best’ match from within the set of applicable methods. If this process does not result in a unique best match, an error (ambiguous match error) is produced.

Selection of Applicable Methods

We start with the complete set of all methods with the required name that exist in the target class or in any of its parent classes (excluding those with identical signatures). From this set, any methods that are not visible from the invoking program, based on the visibility attribute encoded into the method, are discarded as follows:

AttributeVisibility
PRIVATE Visible only if the calling class is the same as the target class
PUBLIC Always visible
PROTECTEDVisible only if the calling class derives from the target class
INTERNAL Visible only if the target class is in the same assembly as the calling class
PROTECTED INTERNAL Visible only if the calling class derives from the target class, or the calling class is in the same assembly as the target

Next, if the required method is an instance method (a method that is applied to an object instance), all static methods are discarded. Similarly, if the required method is a static method, all instance methods are discarded.

Now each method is examined in turn to see whether it is applicable in normal form. This is determined as follows:

  1. If the number of arguments is different from the number of parameters in the method, then this method is discarded.
  2. If the type of the parameter in the target method is MicroFocus.COBOL.Program.Reference (generic COBOL data passed by reference), then any argument type is assumed to match except for .NET native types.
  3. For each argument with an explicit parameter passing mode (BY CONTENT, BY VALUE or BY OUTPUT), that mode must correspond to the definition of the parameter in the method being examined.
  4. For a REFERENCE or OUTPUT parameter, the type of the argument must be exactly the same as the parameter type.

    For a VALUE parameter, an implicit conversion must exist from the type of the argument to the type of the corresponding parameter. If any of these implicit conversions require truncation, this method is said to be a ‘truncation match’. See Implicit Conversion.

If a method is not applicable according to these rules, an attempt is made to match the method in expanded form, if both the following are true:

The expanded form of the method is derived from the normal form by replacing the array parameter by zero or more value parameters of the same type as the array element, so that the total number of parameters is the same as the number of invoking arguments. If the class already contains a method in normal form with this same expanded signature, then this method is determined to be not applicable. Otherwise the expanded form is tested for applicability in the same way as the test for normal form above.

After the above selection procedure:

Selection from Multiple Applicable Methods

The general intent of the selection process is to produce the best match (in the sense of most specific match) for the given set of arguments. For example, suppose class A derives from class B, which itself derives from System.Object. The following example shows how, even in the case where the supplied argument is not exactly the same as that for any of the target methods, the “most specific” rule takes effect.

Class X.
Static.
Method-id. Method1.
Procedure division using by value arg1 as object.   *> method (i)
End method method1.
Method-id. Method1.
Procedure division using by value arg1 as B.   *> method (ii)
End method method1.
End static.
End class X.
Class Y.
Static.
Method-id. Main.
01 obj1 object.
01 obj2 type “B”.
01 obj3 type “A”.
      Invoke type “X”::”Method1”(obj1)  *> Uses method (i)
      Invoke type “X”::”Method1”(obj2)  *> Uses method (ii)
      Invoke type “X”::”Method1”(obj3)  *> also uses method (ii) since type B is ‘closer’ 
                                                                 *> to type A than System.Object…
End method main.
End static.
End class Y.

Formally, the method overload that is ‘better’ than any other of the applicable method overloads is chosen. If no single overload is determined to be better than any other overload, then the match is considered to be ambiguous, and a compiler error results. See Better Method Overload.

Better Method Overload

Suppose we have an argument list A with a set of argument types (A1, A2,…An) and two applicable method overloads Mp and Mq with parameter types (P1…Pn) and (Q1,…Qn), where if necessary the parameters have been converted to expanded form (see above).

Then, Mp is said to be a better method overload than Mq if both the following are true:

Better Conversion

Suppose we have two conversions, from type S to types T1 and T2, then the better conversion is determined as follows:

If the conversion from S to T1 is better than the conversion from S to T2, then it is also true that the conversion from S to T2 is worse than the conversion from S to T1.

Implicit Conversion

An implicit conversion exists from type S to type T if it is possible to assign an object of type S to an object of type T (SET obj-T TO obj-S).

The following types of implicit conversion are available in the .NET system:


Copyright © 2009 Micro Focus (IP) Ltd. All rights reserved.