Errors when calling functions and events dynamically
If you call a
function or event dynamically, different conditions create different results,
from no effect to an execution error. The tables in this section
illustrate this.
Functions
The rules for functions are similar to those for events, except
functions must exist: if a function is not found, an error always
occurs. Although events can exist without a script, if a function
is defined it has to have code. Consider the following statements:
-
This statement calls a function without looking
for a return value:1object.DYNAMIC funcname( ) -
This statement looks for an integer return
value:1int li_int1li_int = object.DYNAMIC funcname( ) -
This statement looks for an Any return
value:1any la_any1la_any = object.DYNAMIC funcname( )
The following table uses these statements as examples.
Condition 1 |
Condition 2 |
Result |
Example |
---|---|---|---|
The function does not exist. |
None. |
Execution error 65: Dynamic function not |
All the statements cause error 65. |
The function is found and executed but |
The code is looking for a return value. |
Execution error 63: Function/event |
Statements 2 and 3 cause error 63. |
Events
Consider these statements:
-
This
statement calls an event without looking for a return value:1object.EVENT DYNAMIC eventname( ) -
This example looks for an integer return
value:1int li_int1li_int = object.EVENT DYNAMIC eventname( ) -
This example looks for an Any return
value:1any la_any1la_any = object.EVENT DYNAMIC eventname( )
The following table uses these statements as examples.
Condition 1 |
Condition 2 |
Result |
Example |
---|---|---|---|
The event does not exist. |
The code is not looking |
Nothing; the call fails silently. |
Statement 1 fails but does not cause |
The code is looking for |
A null of the Any datatype |
La_any is |
|
If the expected datatype is not Any, execution |
The assignment to li_int causes execution |
||
The event is found but is |
The event has a defined |
A null of the defined datatype |
If eventname is defined to return integer, li_int is set |
The event does |
A null of the Any datatype |
La_any is |
|
If the expected datatype is not Any, execution |
The assignment to li_int causes execution |
||
The event is found and executed but is not |
The code is looking for a return value. |
Execution error 63: Function/event |
Statements 2 and 3 cause error 63. |
When an error occurs
You can surround a dynamic function call in a try-catch block
to prevent the application from terminating when an execution error
occurs. Although you can also handle the error in the SystemError
event, you should not allow the application to continue once the
SystemError event is invoked—the SystemError event should
only clean up and halt the application.
For information on using try-catch blocks, see the chapter
on exception handling in Application Techniques.
If the arguments do not match
Function arguments are part of the function’s definition.
Therefore, if the arguments do not match (a compatible match, not
an exact match), it is essentially a different function. The result
is the same as if the function did not exist.
If you call an event dynamically and the arguments do not
match, the call fails and control returns to the calling script.
There is no error.
Error-proofing your code
Calling functions and events dynamically opens up your application
to potential errors. The surest way to avoid these errors is to
always make static calls to functions and events. When that is not
possible, your design and testing can ensure that there is always
an appropriate function or event with the correct return datatype.
One type of error you can check for and avoid is data conversion
errors.
The preceding tables illustrated that a function or event
can return a null value either as an Any variable
or as a variable of the expected datatype when a function or event
definition exists but is not implemented.
If you always assign return values to Any variables
for dynamic calls, you can test for null (which
indicates failure) before using the value in code.
This example illustrates the technique of checking for null before
using the return value.
1 |
any la_any<br>integer li_gotvalue<br>la_any = object.DYNAMIC uf_getaninteger( )<br>IF IsNull(la_any) THEN<br>   ... // Error handling<br>ELSE<br>   li_gotvalue = la_any<br>END IF |