Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based Objects : Assigning object references : Object reference assignment and casting
 

Object reference assignment and casting

As described in the previous section, you can assign a source object reference to a target object reference data element if the target data element is defined as the same class, a super class, or an interface of the source object. When the target data element is defined for a super class or interface, an implicit cast is done by the AVM at run time. The word cast, as used in object-oriented terminology, can be compared to the cast of a play, in which each actor is assigned a role. When you program with classes, each reference to an object must identify the role that the object is required to play, as identified by its data type. The compiler verifies that no object reference is allowed to act contrary to its assigned role and access a data member, property, method, or event not defined by its data type.
Using a super class object reference, rather than an object reference to a specific subclass, allows you to take advantage of any polymorphic behavior implemented by available subclasses. Thus, you can assign a subclass instance to an object reference for a given super class. When you invoke any method on this super class object reference, the subclass implementation of that method executes, depending on the particular subclass instance that you have assigned. By implicitly casting the assignment of the subclass to the super class object reference, ABL enables transparent access to this polymorphic behavior. (For more information on polymorphism, see Usingpolymorphism with classes.)
Similarly, using an interface object reference, rather than an object reference to a specific class that implements that interface, allows you to take advantage of any polymorphic behavior provided by all classes that implement the same interface. Thus, you can assign a class object reference to a data element defined as a given interface type. When you invoke any method on the assigned interface object reference, the implementation of that method for the actual class instance executes, depending on the particular class instance that you have assigned. By implicitly casting the assignment of the class to the interface object reference, ABL enables transparent access to this polymorphic behavior.
Again, ABL permits all of these assignments from a subclass reference to a super class-type data element, or from an implementing-class reference to an interface-type data element, because the very nature of subclass inheritance and class interface implementation guarantees that PUBLIC and PROTECTED members provided by the respective super class and interface object references must work.
For example, refer to the following class hierarchy:
Progress.Lang.Object           <--- Top of hierarchy
  acme.myObjs.Common.CommonObj
    acme.myObjs.CustObj
      acme.myObjs.NECustObj    <--- Bottom of hierarchy
You can directly assign an acme.myObjs.NECustObj object reference to either an acme.myObjs.CustObj, acme.myObjs.Common.CommonObj or Progress.Lang.Object data element. You can also directly assign an acme.myObjs.CustObj object reference to an acme.myObjs.Common.CommonObj or Progress.Lang.Object data element.
Sometimes it is necessary to cast downward—that is, to take an object reference for a super class or interface in a class hierarchy and assign it to a data element defined as a subclass or interface-implementing class further down the class hierarchy. As noted, the compiler will not do this implicitly when you perform an assignment or pass a parameter, because it cannot verify that references to the object will all be valid.
To explicitly cast an object reference downward, use either the CAST function or the DYNAMIC-CAST function. You can use either of these two functions to implement a cast. However, a cast using the CAST function is initially validated at compile time, while the same cast using the DYNAMIC-CAST function is validated only at run time.
For the cast to work:
*An initial super class object reference must actually point to an instance of the subclass to which you are casting
*An initial interface object reference must actually point to the class instance to which you are casting, and that class instance must implement the interface type of the initial object reference
Thus, you can only cast an object reference downward when the object was originally instantiated as the target class or one of its subclasses. This means that you must know that a super class object reference, at run time, is really an object reference to a subclass instance or that an interface object reference is really an object reference to an interface-implementing class instance.
Note: While you must use the CAST or DYNAMIC-CAST function to cast downward, you can also use these functions to cast upward. However, this is typically not necessary because, as already noted, ABL automatically casts object reference assignments upward.
Casting tells ABL to trust your judgment and allow the downward cast within the specified class hierarchy. However, the AVM checks at run time to ensure that a downward cast is valid. For example, if a super class object reference is not pointing to an instance of the specified subclass, the AVM returns a run-time error. This means that when you use the CAST (or DYNAMIC-CAST) function, you are bypassing some (or all for DYNAMIC-CAST) of the compiler's checks for validity of object references. This increases the flexibility of how you can assemble different classes and let them interoperate, but with increased responsibility on your part to make sure that all types are valid at run time.
In addition to validation, the CAST and DYNAMIC-CAST functions each have some different usage requirements.