Error management in the Gambas programming language also includes the topics of recognising errors, catching errors and handling errors. For this purpose, Gambas provides the instructions TRY, FINALLY, CATCH, ERROR, DEBUG as well as the error class Error, a global, read-only Boolean variable Error and error numbers as well as error descriptions, which are described in this chapter.
The Error class has these static, read-only properties:
Property | Data type | Description |
---|---|---|
Backtrace | String[] | Returns a backtrace of the stack state of the function call when the last error occurred. The first entry of the string array is the lowest function call. If no debugging information was available or if no error occurred, this property returns NULL. |
Class | Class | Returns the name of the class in which the last error occurred. |
Code | Integer | Returns the last error number. |
Text | String | Returns the last error message - corresponding to the associated error code in English. |
Where | String | Returns a string describing the position of the last error in the source code. |
Table 11.5.0.1.1 : Properties of the Error Class
Instead of the Error.Backtrace property of the Error class, you can also use the static property System.Backtrace (gb) with Static Property Read Backtrace As String[ ]. In both cases, a string array is returned to you that you can read out and display.
The Error class Error has only three methods:
Method | Description |
---|---|
Clear() | Sets the error code to 0 and the error message to NULL. You can use this method if you handle the error within a procedure and then set the properties Error.Code to 0 and Error.Text to NULL. |
Propagate() | The method ensures that the error is triggered again. |
Raise( argMessage As String ) | Raises an error defined by the user. The error message in argMessage can be freely defined in the source code. |
Table 11.5.0.1.2 : Methods of the error class
DEBUG Expression [ { ; | ;; | , } Expression ... ] [ { ; | ;; | , } ]
FMain.GetStart.69: /tmp/gambas.1000/13839/New.tmp/new.md.
The following example was about checking various paths. The instruction DEBUG - switched on by the boolean variable bDebug - was preferred to an instruction PRINT, because the line numbers in the source code were also of interest:
Public bDebug As Boolean bDebug = True sBasicConfigDir = Desktop.ConfigDir &/ sVendor &/ Lower(sAppName) If bDebug Then Debug sBasicConfigDir If Not Exist(sBasicConfigDir) Then Shell.MkDir(sBasicConfigDir) hSettings = New Settings(sBasicConfigDir &/ File.SetExt(Lower(sAppName), "conf")) If bDebug Then Debug sBasicConfigDir &/ File.SetExt(Lower(sAppName), "conf") ... sCurrentMDFilePath = sTempDir &/ "new.md" If bDebug Then Debug sCurrentMDFilePath
Outputs in the console of the IDE:
FMain._new.49: /home/hans/.config/gambasbook/mdeditor FMain._new.52: /home/hans/.config/gambasbook/mdeditor/mdeditor.conf ... FMain.GetStart.69: /tmp/gambas.1000/13839/New.tmp/new.md
===== 11.5.0.1.3 Statement ERROR =====<code_b_3>
The statement prints a list of expressions on the standard error output - just like the PRINT statement. If you were writing a command-line program, this statement would be the non-graphical equivalent of Message.Error().
If in the IDE, in the Debug menu, you activate the entries 'Use Terminal Emulator' and “Redirect Standard Error Output” both with ✔, then DEBUG and ERROR output will be displayed in the IDE console and PRINT output in the terminal. However, if 'Use terminal emulator' is active and redirection is disabled, then DEBUG, ERROR and PRINT output will be displayed in the terminal:
Figure 11.5.0.1.1: DEBUG, ERROR and PRINT outputs in the (IDE) terminal.
The standard output can be redirected by the ERROR TO statement ( ▷ chapter 6.2.0.14 ERROR TO DEFAULT). A redirection is simply implemented:
DIM aFile As File aFile = OPEN User.Home &/ "error_ping.log" FOR CREATE ' or APPEND OUTPUT TO aFile ... Error ... ... CLOSE aFile
This source code snippet redirects the output of the error statement to the specified file.
The boolean variable Error - global and read-only - returns the value True if an error has occurred. Use it directly after a Try statement to know whether the statement specified there failed or not. To get more information about the error, use the (error) class Error (gb) with success.
Example: Deleting a file
Public Sub btnKillFile_Click() Dim sMessage, sFilePath As String sFilePath = User.Home &/ "Temp" &/ "tmp.text" Try Kill sFilePath If Error Then Print "Error! The file `" & File.Name(sFilePath) & "` cannot be deleted!" If Error Then Error Subst("&1 '&2' &3", ("Error! The file"), File.Name(sFilePath), ("cannot be deleted!")) If Error Then Print Error.Class.Name;; Error.Code;; Error.Text;; Error.Where If Error Then Error "Error³!";; Error.Text If Error Then Error Error If Error Then Debug Error.Text '-------------------------------------------------------------------------------------------------------- If Error Then sMessage = "<b><font size='+1', color='DarkRed'>" sMessage &= ("Error") sMessage &= "</b></font><hr>" sMessage &= "The file '" & File.Name(sFilePath) & "' cannot be deleted.<br>" sMessage &= Error.Text & "!<br>" sMessage &= ("The error was raised in the source code line") & " " & Split(Error.Where, ".")[2] & "." Message.Error(sMessage) Endif '-------------------------------------------------------------------------------------------------------- Error Error End
The following is the output in the console of the IDE:
Error! The file `tmp.text` cannot be deleted! Error! The file 'tmp.text' cannot be deleted! FMain 45 File or directory does not exist FMain.btnKillFile_Click.10 Error³! File or directory does not exist True FMain.btnKillFile_Click.16: File or directory does not exist True
Figure 11.5.0.1.2: Error message
Comment
If Error Then Error Error
' Gambas class file Property Read Basis As Integer Private $iBasis As Integer Private Function Basis_Read() As Integer If FSetBasisDialog.ShowModal() = 1 Then Return $iBasis Else Return 0 Endif End Public Sub Form_Open() FSetBasisDialog.Resizable = False End Public Sub txbBasis_Activate() SetBasis() End Public Sub btnOK_Click() SetBasis() End Private Function CheckInput(argInput As String) As Integer Dim iValue As Integer If Not argInput Then Error.Raise(("Die Eingabebox ist leer!")) If Not IsInteger(argInput) Then Error.Raise(("Der Text kann <b>nicht</b> in eine Integer-Zahl konvertiert werden!")) EndIf iValue = Val(argInput) If iValue < 2 Then Error.Raise(("Die Basis ist kleiner als 2!")) If iValue > 32 Then Error.Raise(("Die Basis ist größer als 32!")) Return iValue End Private Sub SetBasis() $iBasis = CheckInput(txbBasis.Text) FSetBasisDialog.Close(1) Catch Message.Error(Error.Text) Error.Clear() txbBasis.Clear() txbBasis.SetFocus() End
Comment
Preliminary note: In the source code of Gambas 3.12.2 you will not find a line with the method Error.Clear() and only 3 times the method Error.Propagate() is used. That says a lot about the importance of these two methods!
When an error is raised, the Gambas interpreter stops the execution of the current frame and looks for error handlers such as try or catch. If it cannot find them, the interpreter goes up the call stack and looks for error handlers there one by one until the global level is reached. There, as a last resort, the interpreter looks for the method `Static Public Sub Application_Error()` in the Start class. If the error could not be corrected, the interpreter issues an error message and terminates the programme.
To observe the automatic unwinding of the stack, look at the following module source code and the resulting output:
' Gambas module file Public Sub Main() f() End Public Sub f() Try g() If Error Then Print "\nError-Backtrace:\n----------------" Print Error.Backtrace.Join("\n") Endif End Public Sub g() h(4) Print "Error from h(arg) will jump over this. Jumps to FINALLY" Finally Print "\nPassing through g()" ' Error.Clear() Error.Propagate() ' Apparently handles the error by triggering it again. End Public Sub h(x As Integer) Print "x = "; CStr(x); " | f(x) = "; 1 / x h(x - 1) ' Recursion - but without termination condition Print "Execution of h stops for x = 0 before we're here!" End
Outputs in the IDE console:
x = 4 | f(x) = 0,25 x = 3 | f(x) = 0,33333333333333 x = 2 | f(x) = 0,5 x = 1 | f(x) = 1 Passing through g() Error-Backtrace: ---------------- Main.h.27 Main.h.28 Main.h.28 Main.h.28 Main.h.28 Main.g.16 Main.f.8 Main.Main.4
You could say that the Try and Catch statements take the interpreter out of the exceptional state. Unwinding of the batch is stopped and normal execution resumes. But if you have several “If Error Then” constructs in the source code, then you must use the Error.Clear() method after handling an error to avoid handling it again! For comparison, comment out the line calling the Error.Clear() method and then look at the output again!
Within an error handler, you can also target the displayed error numbers, which you can read via the Error.Code property of the Error (gb) class. For a complete list, see http://gambaswiki.org/wiki/error. Use the error numbers to generate meaningful error messages in German, because behind each error number is a short description of the triggered error in English, as the following examples show as an example:
(43) Access forbidden (44) File name is too long (45) File or directory does not exist (46) File is a directory (47) Read error (48) Write error
Cannot find dynamic library (60) Cannot find symbol in dynamic library (61) Cannot load class (2) Cannot load component (27) Cannot open file (35)
The following source code excerpt sets an error message in German in the Select…Case control structure in the Catch block for selected error numbers. The error number is read from the Error.Code property:
Public Sub btnSaveFile_Click() ' -> Saves the content of TextArea1 in the file to which the path in TextBox1 leads. Dim hFile As Stream Dim iCount As Integer Dim sErrorText As String hFile = Open TextBox1.Text For Write ... Write #hFile, bWrite, 1 ... ' -> Close the stream in any case Finaly Close #hFile Catch Select Case Error.Code Case 43 sErrorText = ("You do not have the rights to save this file.") Case 44 sErrorText = ("The file name is too long.") Case 45 sErrorText = ("The file or folder does not exist.") Case 46 sErrorText = ("The path leads to a folder.") Case 48 sErrorText = ("Error when writing to the file.") Case Else sErrorText = "" End Select ' -> Output information about the triggered error Message.Error("Error-Code: " & Error.Code & "\n" & "bei " & Error.Where & "\n" & sErrorText) End
Projects