Tips_tutorials   >   Studio103   >   Error Handling Code Guidelines
Adding the $promptonceLastError code to the visual class methods was relatively easy because the methods were written with a single exit point at the end of the method.
For the first few years of writing code in Omnis Studio I wrote methods with multiple exit points. Steve McConnell in his excellent book,
, pointed out that code with multiple exit points is difficult to read and statistically has a greater number of errors. I switched to writing methods which have a single exit point at the end of the method and have to agree with Steve's findings.Here is a sample of how I used to write code with multiple exits points.
; Check the incoming parameter
If pReportList.$linecount=0
Calculate Mssg as "The report list is empty, unable to print the report."
Do $ctask.errhndler.$logError($cmethod,Mssg)
Quit method kFalse
End If
; Check the records in the list.
For pReportList.$line from 1 to pReportList.$linecount step 1
Do method checkData (pReportList) Returns FlagOK
If not(FlagOK)
; The called method will have logged an error.
Quit method kFalse
End If
End For
; Find the report class for printing the report.
Do $clib.$reports.$findname(pReportClassName) Returns rClass
If isnull(rClass)
Calculate Mssg as con("Unable to find the specified report class, ",pReportClassName,".")
Do $ctask.errhndler.$logError($cmethod,Mssg)
Quit method kFalse
End If
; If we get this far we can print the report.
Set report name [pReportClassName]
Print report {(pReportList)}
Quit method kTrue
Here is a sample of how I now write code with a single exit points.
; Note: The FlagOK parameter init value is always set to kFalse.
; Check the incoming parameter
If pReportList.$linecount=0
Calculate Mssg as "The report list is empty, unable to print the report."
Else
; Preset the flag to true before the loop.
Calculate FlagOK as kTrue
; Check for any inactive records from the list.
For pReportList.$line from 1 to pReportList.$linecount step 1
Do method checkData (pReportList) Returns FlagOK
If not(FlagOK)
; The called method will have logged an error.
Break to end of loop
End If
End For
If FlagOK
; Find the report class for printing the report.
Do $clib.$reports.$findname(pReportClassName) Returns rClass
If isnull(rClass)
Calculate Mssg as con("Unable to find the specified report class, ",pReportClassName,".")
Do $ctask.errhndler.$logError($cmethod,Mssg)
Calculate FlagOK as kFalse
Else
; If we get this far we can print the report.
Set report name [pReportClassName]
Print report {(pReportList)}
End If
End If
End If
Quit method FlagOK
Always return something from a method! If the method is so simple that it can never have an error end the method with Quit method kTrue anyway.
When it come to return value I have two categories of methods:
Communicating an error from these two categories of methods is simple.
Testing the return value from methods that return a flag (true or false) is easy. Depending on the situation you test for If FlagOK (good) or If not(FlagOK) (error).
Do method checkData (List) Returns FlagOK
If FlagOK
Do method saveData (List) Returns FlagOK
End If
Quit method FlagOK
Testing the return value from a method that returns a value is normally easy. Depending on the situation you test for If not(isnull(RetValue)) (good) or If isnull(RetValue) (error).
Do method retClassRef (ClassName) Returns rClass
If isnull(rClass)
Calculate FlagOK as kFalse
Else
Do method openClassInstance (rClass) Returns rInst
If isnull(rInst)
Calculate FlagOK as kFalse
Else
Calculate FlagOK as kTrue
End If
End If
Quit method FlagOK
Testing for isnull() does not work for list and row variables. For lists or rows you must check the $colcount rather than isnull(). If List.$colcount>0 (good), or List.$colcount=0 (error).
; Testing a list or row for isnull() does NOT work.
Do method retDefinedList (SQLClassName) Returns List
If isnull(List)
Calculate FlagOK as kFalse
Else
Do List.$getAllRecords() Returns FlagOK
End If
Quit method FlagOK
; Testing a list or row for $colcount does work.
Do method retDefinedList (SQLClassName) Returns List
If List.$colcount=0
Calculate FlagOK as kFalse
Else
Do List.$getAllRecords() Returns FlagOK
End If
Quit method FlagOK
Ideally, only the following methods send $promptonceLastError messages to the error handler.
For each method you write, carefully decide what is an error, and what is not an error.
Originally when I wrote the $getAllRecords table class method I returned false if no records were fetched. Later as I wrote more application code I ran into situations where a table might not have any records and in that situation it was not an error.
Now I was in trouble, I had to return false because other methods were depending on false to indicate no records were fetched, but for the empty table, this really was not an error.
Eventually I came to the conclusion that for table class methods, fetching zero records should not be considered an error. Only SQL errors and check data errors would be classified as errors. It would be up to the sender method to check the List.$linecount and decide whether or not zero fetched records was a problem for them.
Always specify in the method description the return value and error conditions.
In the StudioWorks framework we eventually added a special class of errors, called minor errors, with an accompanying $logMinorError method. The $logMinorError method adds the minor error to the errors list in RAM, but does not write the error to the log file.
A situation where we would log a minor error is when the non-visual oLogon object is asked by the visual window to $logon to the database, but the user has entered the wrong user name or password. The non-visual oLogon object sends a $logMinorError message to the error handler and returns false to the window. The minor error becomes the current error in the errors list, but is not written to the log file. The window sends a $promptonceLastError message to the error handler and the error handler opens a prompt window with the current error. The prompt window notifies the user that they have entered the wrong user name or password.
In the StudioWorks framework we also added an errortype property to the errors list. The errortype determines the type of error prompt window the user sees. If the errortype is minor the prompt window title doesn't use the word Error, and the error message information does not include the source information of the method which logged the error.
There is a lot you can do to extend the oErrorHandler object which we have built in this tutorial.