Using Caché Objects
Implementing Dynamic Dispatch
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter discusses dynamic dispatch in Caché classes. Topics in this chapter include:

When viewing this book online, use the preface of this book to quickly find other topics.
Introduction to Dynamic Dispatch
Caché classes can include support for what is called dynamic dispatch. If dynamic dispatch is in use and a program references a property or method that is not part of the class definition, then a method (called a dispatch method) is called that attempts to resolve the undefined method or property. For example, dynamic dispatch can return a value for a property that is not defined or it can invoke a method for a method that is not implemented. The dispatch destination is dynamic in that it does not appear in the class descriptor and is not resolved until runtime.
Caché makes a number of dispatch methods available that you can implement. Each method attempts to resolve an element that is missing under different circumstances.
If you implement a dispatch method, it has the following effects:
Content of Methods Implementing Dynamic Dispatch
As the application developer, you have control over the content of dispatch methods. The code within them can be whatever is required to implement the methods or properties that the class is attempting to resolve.
Code for dynamic dispatch might include attempts to locate a method based on other classes in the same extent, package, database, on the same file system, or by any other criteria. If a dispatch method provides a general case, it is recommended that the method also create some kind of log for this action, so that there is a record of any continued operation that includes this general resolution.
For example, the following implementation of %DispatchClassMethod() allows the application user to invoke a method to perform whatever action was intended:
ClassMethod %DispatchClassMethod(Class As %String, Method As %String, args...)
{
    WRITE "The application has attempted to invoke the following method: ",!,!
    WRITE Class,".",Method,!,!
    WRITE "This method does not exist.",!
    WRITE "Enter the name of the class and method to call",!
    WRITE "or press Enter for both to exit the application.",!,!


    READ "Class name (in the form 'Package.Class'): ",ClassName,!
    READ "Method name: ",MethodName,!
    
    IF ClassName = "" && MethodName = "" {
        // return a null string to the caller if a return value is expected
        QUIT:$QUIT "" QUIT
    } ELSE {
        // checking $QUIT ensures that a value is returned 
        // if and only if it is expected
        IF $QUIT {
            QUIT $CLASSMETHOD(ClassName, MethodName, args...)
        } ELSE {
            DO $CLASSMETHOD(ClassName, MethodName, args...)
            QUIT
        }
    }
}
By including this method in a class that is a secondary superclass of all classes in an application, you can establish application-wide handling of calls to nonexistent class methods.
Return Values
None of the dispatch methods have specified return values. This is because each should provide output that is of the same type of the call that originally created the need for the dispatch.
If the dispatch method cannot resolve the method or property, it can use $ZUTIL(96,3) to throw a <METHOD DOES NOT EXIST> or <PROPERTY DOES NOT EXIST> error — or whatever else may be appropriate.
The Dynamic Dispatch Methods
The following methods may be implemented to resolve unknown methods and properties:
%DispatchMethod()
This method implements an unknown method call. Its syntax is:
Method %DispatchMethod(Method As %String, Args...)
where its first argument is the name of the referenced method and the second argument is an array that holds all the arguments passed to the original method. Since the number of arguments and their types can vary depending on the method being resolved, the code in %DispatchMethod() needs to handle them correctly (since the class compiler cannot make any assumptions about the type). The Args... syntax handles this flexibly.
Because %DispatchMethod() attempts to resolve any unknown instance method associated with the class, it has no specified return value; if successful, it returns a value whose type is determined by the method being resolved and whether the caller expects a return value.
%DispatchMethod() can also resolve an unknown multidimensional property reference — that is, to get the value of a property. However, only direct multidimensional property references are supported for dynamic dispatch. $DATA, $ORDER, and $QUERY are not supported, nor is a SET command with a list of variables.
%DispatchClassMethod()
This method implements an unknown class method call. Its syntax is:
ClassMethod %DispatchClassMethod(Class As %String, Method As %String, Args...)
where its first two arguments are the name of the referenced class and the name of the referenced method. Its third argument is an array that holds all the arguments passed to the original method. Since the number of arguments and their types can vary depending on the method being resolved, the code in %DispatchClassMethod() needs to handle them correctly (since the class compiler cannot make any assumptions about the type). The Args... syntax handles this flexibly.
Because %DispatchClassMethod() attempts to resolve any unknown class method associated with the class, it has no specified return value; if successful, it returns a value whose type is determined by the method being resolved and whether the caller expects a return value.
%DispatchGetProperty()
This method gets the value of an unknown property. Its syntax is:
Method %DispatchGetProperty(Property As %String)
where its argument is the referenced property. Because %DispatchGetProperty() attempts to resolve any unknown property associated with the class, it has no specified return value; if successful, it returns a value whose type is that of the property being resolved
%DispatchSetProperty()
This method sets the value of an unknown property. Its syntax is:
Method %DispatchSetProperty(Property As %String, Value)
where its arguments are the name of the referenced property and the value to set for it.
%DispatchSetMultidimProperty()
This method sets the value of an unknown multidimensional property. Its syntax is:
Method %DispatchSetMultidimProperty(Property As %String, Value, Subs...)
where its first two arguments are the name of the referenced property and the value to set for it. The third argument, Subs, is an array that contains the subscript values. Subs has an integer value that specifies the number of subscripts, Subs(1) has the value of the first subscript, Subs(2) has the value of the second, and so on. If no subscripts are given, then Subs is undefined.
Only direct multidimensional property references are supported for dynamic dispatch. $DATA, $ORDER, and $QUERY are not supported, nor is a SET command with a list of variables.
Note:
Note that there is no %DispatchGetMultidimProperty() dispatch method. This is because a multidimensional property reference is identical to a method call. Thus, such a reference invokes %DispatchMethod(), which must include code to differentiate between method names and multidimensional property names.