In the following contrived examples, one class (Derived) inherits behavior from another class (Base), each of which can halt object instantiation for different reasons that are each handled by the instantiating procedure (instantiater2.p):
CLASS Base:
CONSTRUCTOR PUBLIC Base ( ):
FIND FIRST Customer NO-ERROR. IF NOT AVAILABLE(Customer) THEN
RETURN ERROR "No records found".
/* Do any further Base class initialization */
END CONSTRUCTOR.
END CLASS.
CLASS Derived INHERITS Base:
CONSTRUCTOR PUBLIC Derived(INPUT iName AS CHARACTER, OUTPUT id AS INTEGER):
SUPER( ). /* Unnecessary, but called for illustration */
FIND Customer WHERE Customer.NAME BEGINS iName NO-ERROR. IF NOT AVAILABLE(Customer) THEN
RETURN ERROR "Specified record not found".
ELSE id = customer.cust-num.
/* Do any further Derived class initialization. */
END CONSTRUCTOR.
END CLASS.
/* instantiator2.p */
DEFINE VARIABLE id AS INTEGER NO-UNDO.
DEFINE VARIABLE rDerived AS CLASS Derived NO-UNDO.
rDerived = NEW Derived ("fred", OUTPUT id).
/* Do normal application processing */ . . .
CATCH e AS Progress.Lang.AppError: IF e:ReturnValue = "Specified record not found" . . .
ELSE IF e:ReturnValue = "No records found" . . .
END CATCH.
The instantiater2.p, procedure knows if the Derived class is not instantiated properly by catching any application error objects thrown for an ERROR condition raised on the NEW statement that instantiates the object. If there are no records in the Customer table, object instantiation fails when its super class constructor tries to find the first record in the table, which the constructor traps and raises ERROR using RETURN ERROR with an appropriate error return string. If the application-specified record is not found in the Customer table, object instantiation fails when the Derived class constructor traps the error and raises ERROR using RETURN ERROR with another appropriate error return string. In the latter case, the AVM also runs the default destructor for the Base class to undo its instantiation. The instantiating procedure, instantiater2.p, can then catch any thrown AppError object and check its ReturnValue property for the type of error that caused the instantiation failure. (RETURN ERROR automatically creates and throws a Progress.Lang.AppError object as part of raising ERROR.)
Thus, ABL error handling (structured or traditional) provides a common mechanism that you can use to handle errors at any level of an instantiating class hierarchy.