Try OpenEdge Now
skip to main content
Object-oriented Programming
Overloaded Method and Constructor Calling Scenarios : Object reference parameters matching a class hierarchy or interface
 

Object reference parameters matching a class hierarchy or interface

ABL searches first for an exact object type match between the passed object reference and the corresponding parameter definition (class type to class type or interface type to interface type). If no exact object type match is found, it searches for a method or constructor whose corresponding parameter definition is for a class type that is a super class in the same class hierarchy as the passed object reference. If there is more than one such super class type represented for that parameter, ABL chooses the method or constructor whose corresponding parameter matches the most derived (closest) of those super classes to the class type of the passed object reference. Failure to find a match raises a compile-time error.
However, there are situations where passing object reference parameters can cause ABL to raise a compile-time ambiguity error, where the corresponding parameters of overloaded methods or constructors define multiple super class and interface type parameter combinations that the class type of the passed object reference parameter inherits and implements, respectively. In such cases, there is no way for ABL to tell what combination of parameters represent the best match for the passed object reference parameters, because more than one combination of parameter definitions can satisfy the combination of passed object reference parameters equally well. In general, if the corresponding parameters of overloaded methods differ by an interface, ABL only accepts an exact object type match to the passed object reference parameter.
For more information on defining and passing object reference parameters, see Defining an object reference parameter and Passingobject reference parameters.
The following examples define method (or constructor) overloadings that take different combinations of class type and interface type parameters and describes how they respond to invocations that pass object references as a variety of related object types.
This example shows method calls to overloaded methods distinguished by object reference parameters whose class types are related to the following single class hierarchy:
ClassA                          <--| Super Classes
  ClassB INHERITS ClassA        <--|
    ClassC INHERITS ClassB      <--|
      ClassD INHERITS ClassC    <-- Most Derived Class
The following class defines three overloadings of the setClass( ) method that take class type parameters from this hierarchy:
CLASS MonoClass:
  METHOD PUBLIC VOID setClass (INPUT prObj AS ClassA):
    MESSAGE "setClass in ClassA".
  END METHOD.

  METHOD PUBLIC VOID setClass (INPUT prObj AS ClassB):
    MESSAGE "setClass in ClassB".
  END METHOD.

  METHOD PUBLIC VOID setClass (INPUT prObj AS ClassD):
    MESSAGE "setClass in ClassD".
  END METHOD.
END CLASS.
The following procedure invokes different overloads of this setClass( ) method:
DEFINE VARIABLE rClassA AS CLASS ClassA       NO-UNDO.
DEFINE VARIABLE rClassB AS CLASS ClassB       NO-UNDO.
DEFINE VARIABLE rClassC AS CLASS ClassC       NO-UNDO.
DEFINE VARIABLE rClassD AS CLASS ClassD       NO-UNDO.
DEFINE VARIABLE rOne    AS CLASS MonoClass( ) NO-UNDO.

ASSIGN
  rClassA = NEW ClassA( )
  rClassB = NEW ClassB( )
  rClassC = NEW ClassC( )
  rClassD = NEW ClassD( )
  rOne    = NEW MonoClass( ).

rOne:setClass( rClassA ). /* 1 */
rOne:setClass( rClassB ). /* 2 */
rOne:setClass( rClassC ). /* 3 */
rOne:setClass( rClassD ). /* 4 */
Execution of the procedure results in the following messages displayed with numbers corresponding to the bold-faced code comments:
1. "setClass in ClassA" — Matches the ClassA parameter
2. "setClass in ClassB" — Matches the ClassB parameter
3. "setClass in ClassB" — Matches the ClassB parameter, as there is no ClassC version
4. "setClass in ClassD" — Matches the ClassD parameter
The examples that follow show method calls to overloaded methods distinguished by object reference parameters whose class types represent super classes and most derived classes from two different class hierarchies that share the same super classes:
ClassZ                        <--| Super Classes of ClassX and ClassW
  ClassY INHERITS ClassZ      <--|
    ClassX INHERITS ClassY    <-- Most Derived Class of ClassX Hierarchy
    ClassW INHERITS ClassY    <-- Most Derived Class of ClassW Hierarchy
The following class defines three overloadings of the setClasses( ) method, each of which take two class type parameters from this hierarchy:
CLASS BiClass:
  METHOD PUBLIC VOID setClasses (INPUT prObjY AS ClassY,
                                 INPUT prObjX AS ClassX):
    MESSAGE "First".
  END METHOD.

  METHOD PUBLIC VOID setClasses (INPUT prObjX AS ClassX,
                                 INPUT prObjY AS ClassY):
    MESSAGE "Second".
  END METHOD.

  METHOD PUBLIC VOID setClasses (INPUT prObjY1 AS ClassY,
                                 INPUT prObjY2 AS ClassY):
    MESSAGE "Third".
  END METHOD.
END CLASS.
The following procedure invokes different overloads of this setClasses( ) method:
DEFINE VARIABLE rObjW AS CLASS ClassW     NO-UNDO.
DEFINE VARIABLE rObjX AS CLASS ClassX     NO-UNDO.
DEFINE VARIABLE rTwo  AS CLASS BiClass( ) NO-UNDO.

ASSIGN
  rObjW = NEW ClassW( )
  rObjX = NEW ClassX( )
  rTwo  = NEW BiClass( ).

rTwo:setClasses(rObjW, rObjW). /* 1 */
rTwo:setClasses(rObjX, rObjX). /* 2 */
rTwo:setClasses(rObjW, rObjX). /* 3 */
rTwo:setClasses(rObjX, rObjW). /* 4 */
The two calls to these setClasses( ) methods resolve as follows, according to the bold-faced code comments:
1. Matches third version of setClasses( ). This is the only possible match.
2. Matches the first and second versions of setClasses( ), because each version has an exact match in one of its two parameters (first or second). ABL cannot choose one over the other, resulting in a compile-time ambiguity error.
3. Matches the first version of setClasses( ). The call matches both the first and third versions, but the first version is a better match because the second parameter is an exact match.
4. Matches the second version of setClasses( ). The call matches both the second and third versions, but the second version is a better match because the first parameter is an exact match.
The following class defines four overloadings of the setClasses( ) method, each of which takes three class type parameters from the same hierarchy:
CLASS TriClass:
  METHOD PUBLIC VOID setClasses (INPUT prObjX AS ClassX,
                                 INPUT prObjY AS ClassY,
                                 INPUT prObjZ AS ClassZ):
    MESSAGE "First".
  END METHOD.

  METHOD PUBLIC VOID setClasses (INPUT prObjX AS ClassX,
                                 INPUT prObjZ AS ClassZ,
                                 INPUT prObjY AS ClassY):
    MESSAGE "Second".
  END METHOD.

  METHOD PUBLIC VOID setClasses (INPUT prObjX  AS ClassX,
                                 INPUT prObjY1 AS ClassY,
                                 INPUT prObjY2 AS ClassY):
    MESSAGE "Third".
  END METHOD.

  METHOD PUBLIC VOID setClasses (INPUT prObjX  AS ClassX,
                                 INPUT prObjZ1 AS ClassZ,
                                 INPUT prObjZ2 AS ClassZ):
    MESSAGE "Fourth".
  END METHOD.
END CLASS.
The following procedure invokes one overload of this setClasses( ) method:
DEFINE VARIABLE rThree AS CLASS TriClass( ) NO-UNDO.
DEFINE VARIABLE rObjX  AS CLASS ClassX      NO-UNDO.

ASSIGN
  rObjX  = NEW ClassX( )
  rThree = NEW TriClass( ).

rThree:setClasses(rObjX, rObjX, rObjX).
The call to setClasses( ) matches all four method definitions. However, the third version is the best match because all three of its parameter matches, together, represent the closest match among them.
As noted, previously, using interface types in parameter definitions can easily create ambiguities in calls to overloaded methods. The following examples show calls to overloaded methods whose object reference parameters are distinguished by one or more interface types:
ClassA                                           <-- Super Class
  ClassB INHERITS ClassA IMPLEMENTS InterfaceC   <-- Most Derived Class

ClassF IMPLEMENTS InterfaceC and InterfaceD      <-- Most Derived Class
This example shows calls within a class definition to two overloaded setObj( ) methods distinguished by a class type parameter that implements an interface and an interface type parameter that represents the same interface:
CLASS InterClass:
  METHOD PROTECTED VOID setObj (INPUT prObjB AS ClassB):
    MESSAGE "First".
  END METHOD.

  METHOD PROTECTED VOID setObj (INPUT prObjC AS InterfaceC):
    MESSAGE "Second".
  END METHOD.

  METHOD PUBLIC INTEGER test ( ):
    DEFINE VARIABLE rObjB AS CLASS ClassB     NO-UNDO.
    DEFINE VARIABLE rObjC AS CLASS InterfaceC NO-UNDO.

    ASSIGN
      rObjB = NEW ClassB( )
      rObjC = NEW ClassF( ).
    setObj(rObjB). /* 1 */
    setObj(rObjC). /* 2 */
  END METHOD.
END CLASS.
The two calls to these setObj( ) methods resolve as follows, according to the bold-faced code comments:
1. Matches the first method, because the class types of the passed and defined parameters are an exact match
2. Matches the second method, because the interface types of the passed and defined parameters are an exact match
This example shows calls within a class definition to two overloaded setObj( ) methods distinguished by a class type parameter that is the super class of a class type that implements an interface and an interface type parameter that represents the same interface:
CLASS InterClass:
  METHOD PROTECTED VOID setObj (INPUT prObjA AS ClassA):
    MESSAGE "First".
  END METHOD.

  METHOD PROTECTED VOID setObj (INPUT prObjC AS InterfaceC):
    MESSAGE "Second".
  END METHOD.

  METHOD PUBLIC INTEGER test ( ):
    DEFINE VARIABLE rObjB AS CLASS ClassB.
    DEFINE VARIABLE rObjF AS CLASS ClassF.
    rObjB = NEW ClassB( ).
    rObjF = NEW ClassF( ).
    setObj(rObjB). /* 1 */
    setObj(rObjF). /* 2 */
  END METHOD.
END CLASS.
The two calls to these setObj( ) methods resolve as follows, according to the bold-faced code comments:
1. The passed parameter represents a class type that inherits from the class type of the parameter defined for the first method and implements the interface type of the parameter defined for the second method. ABL cannot choose the best match and raises a compile-time ambiguity error.
2. The passed parameter represents a class type that is unrelated to the class type of the parameter defined for the first method (except that they both implement the same interface type), but because it does implement the interface type of the parameter defined for the second method, ABL matches the call to the second method.
This example shows calls within a class definition to two overloaded setObj( ) methods distinguished by parameters defined with two different interface types, where both interfaces are implemented by one class type and one interface is implemented by an unrelated class type:
CLASS InterClass:
  METHOD PROTECTED VOID setObj (INPUT prObjC AS InterfaceC):
    MESSAGE "First".
  END METHOD.

  METHOD PROTECTED VOID setObj (INPUT prObjD AS InterfaceD):
    MESSAGE "Second".
  END METHOD.

  METHOD PUBLIC INTEGER test ( ):
    DEFINE VARIABLE rObjB AS CLASS ClassB NO-UNDO.
    DEFINE VARIABLE rObjF AS CLASS ClassF NO-UNDO.

    ASSIGN
      rObjB = NEW ClassB( )
      rObjF = NEW ClassF( ).

    setObj(rObjB). /* 1 */
    setObj(rObjF). /* 2 */
  END METHOD.
END CLASS.
The two calls to these setObj( ) methods resolve as follows, according to the bold-faced code comments:
1. The passed parameter represents a class type that implements the interface type of the parameter defined for the first method, but not the second. So, ABL matches the call to the first method.
2. The passed parameter represents a class type that implements the interface types of the parameters defined for both methods. ABL cannot choose the best match and raises a compile-time ambiguity error.