Custom Exception Handling

In addition to throwing exceptions when ProcScript errors occur, you can define your own exceptions using the throw or throw/list statements.

These commands enable you to define an error number that is returned in $procerror, and a brief error description and additional information that is returned in $procerrorcontext, just like Uniface ProcScript errors.

To ensure that custom error numbers do not conflict with Uniface error numbers, use negative integers outside the range -1..-9999.

Example: Throwing a Custom Exception

For example, the following example includes a custom check to ensure that profile data is provided (not ""), because that would make the function always return True.

entry dataExists
throws ; Declares that this module throws an exception on any $procerror
returns Boolean
params
  string pEntityName: in
  string pProfileData: in ; “fieldname1=profile1{;...}”
endparams
variables
  string vFieldName, vFieldProfile
  numeric vIndex
endvariables
  clear/e pEntityName
  forlist/id vFieldName, vFieldProfile, vIndex in pProfileData ; 1. Populates fields with profile data
    if (vFieldProfile != "")                           ; 2. Custom check for empty profile  
      @("%%(vFieldName).%%(pEntityName)")/init = vFieldProfile
    else                                               ; 3. Throw a custom exception. See Note 3
      throw -10000, "Profile data not allowed to be null", "PARAM_INDEX=%%(vIndex);PARAM_NAME=%%(pProfileData);FIELD_NAME=%%(vFieldName)"
    endif
  endfor
  try ; introduces code that may result in an error 
    retrieve/e pEntityName
  catch -2, -4 ; catches specific errors and handles them 
    return "F"
  endtry
  return "T"
end

Notes:

  1. Loop that populates the fields with the profile data.
  2. Custom check for null or "".
  3. If the check fails, the throw statement throws a custom error with the following arguments:
    • ErrorNumber, a negative integer that is put in $procerror and the ERROR item of $procerrorcontext.
    • Description, a short error description that is put in the DESCR item of $procerrorcontext. For code readability, define a hard-coded message here.
    • AdditionalInfo, an associative list with more error details that is put in the ADDITIONAL item of $procerrorcontext.

For more information, see throw.

Generalizing Custom Exceptions

Checking for null or empty values is a common requirement, so it makes sense to centralize the exception for general use.

The following example demonstrates how you can use a Global ProcScript to assemble the error information for the exception and then use it in another code module.

entry notNull   ; 1. Global ProcScript in Library 'myExceptions' 
throws          ; 2. Declares that this module throws an exception on any $procerror. See Note 2
returns string  ; 3. Exception details as an associated list
params
  numeric pParamIndex : in
  string pParamName   : in
  string pFieldName   : in
endparams
variables
  string vException  ; The exception details as an associative list
endvariables

  putitem/id vException, "ERROR", -10000
  putitem/id vException, "DESCRIPTION", "Profile data not allowed to be null"
  putitem/id vException, "ADDITIONAL", "PARAM_INDEX=%%(pParamIndex);PARAM_NAME=%%(pProfileData);FIELD_NAME=%%(pFieldName)"

  return vException
end
  1. The notNull entry is defined in a Global ProcScript in Library called myExceptions.

    Tip: It is good practice to create a dedicated Global Proc library for all your custom exceptions.

  2. It is also good practice to always add a throws declaration to script modules. This ensures that if you have made a mistake in writing the code, it is reported as soon as you test it.
  3. The Global ProcScript returns a string that holds an associative list of format with the error information which can be passed as the argument with a throw/list statement
  4. The code uses the IN parameters passed by the calling module to construct the associative list for the exception details. These IN parameters are specific to this notNull exception.

The entry dataExists can now use the notNull Global ProcScript in a throw/list command. The throw/list statement takes the return value of the myException::notNull() Global ProcScript as argument. (Remember that the entries can be used as functions).

entry dataExists
throws ; Declares that this module throws an exception on any $procerror
returns Boolean
params
  string pEntityName: in
  string pProfileData: in ; “fieldname1=profile1{;...}”
endparams
variables
  string vFieldName, vFieldProfile
endvariables
  clear/e pEntityName
  forlist/id vFieldName, vFieldProfile, vIndex in pProfileData
    if (vFieldProfile != "")   ; 2. Custom check for empty profile.
      @("%%(vFieldName).%%(pEntityName)")/init = vFieldProfile
    else    ; Throw a custom exception
      throw/list myExceptions::notNull(2, vFieldProfile, vFieldName)
    endif
  endfor

  try ; Introduces code that may result in an error 
    retrieve/e pEntityName
  catch -2, -4 ; Catches specific errors and handles them 
    return "F"
  endtry
  return "T"
end

For more information, see throw/list.