Try ... Catch ... Finally

I’m busy refactoring and moving the code forward to API 2.

In converting LastError to the exception, I’m converting to Try … Catch … Finally … End Try. Just looking at best practice in a scenario such as this:

If f <> Nil And Not f.Exists Then
  theTOS = TextOutputStream.Create(f)
  If theTOS.LastErrorCode <> 0 Then
    MsgBox "Can't create safe temporary list file."
    Return Nil
  Else
    If defaultEntry <> "" Then
      theTOS.Write defaultEntry + EndOfLine.UNIX
    Else
      theTOS.Write "" + EndOfLine
    End If
    theTOS.Flush
    theTOS.Close
  End If
End If

In the conversion, which is the better path:

If f <> Nil And Not f.Exists Then
  Try
    theTOS = TextOutputStream.Create(f)
  Catch e As NilObjectException
    MsgBox "Can't create safe temporary list file."
    Return Nil
  Catch e As IOException
    // Permissions issue?
  Finally
    If defaultEntry <> "" Then
      theTOS.Write defaultEntry + EndOfLine.UNIX
    Else
      theTOS.Write "" + EndOfLine
    End If
    theTOS.Flush
    theTOS.Close
  End Try
End If

Or

If f <> Nil And Not f.Exists Then
  Try
    theTOS = TextOutputStream.Create(f)
  Catch e As NilObjectException
    MsgBox "Can't create safe temporary list file."
    Return Nil
  Catch e As IOException
    // Permissions issue?
  End Try
  If defaultEntry <> "" Then
    theTOS.Write defaultEntry + EndOfLine.UNIX
  Else
    theTOS.Write "" + EndOfLine
  End If
  theTOS.Flush
  theTOS.Close    
End If

If you’ve got an IOException, something went wrong with creating the file and you can’t use theTOS. Trying to write in the finally block (or just afterwards) is going to raise another exception, so you want to catch the exception after you’re done writing.

Really simply, written in the forum editor:

try
  theTOS = TextOutputStream.Create(f)
  theTOS.Write("stuff")
  theTOS.Close

catch ex as IOException
  // Something bad happened, tell the user or do something safe within a thread

end try
2 Likes

Also, since you previously checked for f <> Nil, you don’t have to catch a NilObjectException. It’ll never happen.

Finally is for stuff you intend to do whether there was an exception or not.

myself using also a boolean in return if the method was executed fine or flase if there was an error. its useful to handle the program flow.

as example

var f As FolderItem = GetTemporaryFile()
if SaveFile(f) = True then
else
endif

instead of messagebox please use a error window with a list
or every error a messagebox popup dialog would annoying the user when a method was called in a loop 100 times.

xojo have also a simplified error handling i found a excel docu, its useful too
Exception err As OLEException

In which case, what is the point of Finally?

Finally is usually used for freeing resources created in the Try block.

I feel like the TextOutputStream.Close call should go in “finally”. Because if the IOException happens during the write operation, the stream should still be closed. theTOE should still be checked for Nil before use.

@Tim_Hare

Can’t the “theTOS” TextOutputStream object be Nil? Wouldn’t that be caught by the:

Catch e As NilObjectException

statement?

I would probably tend to put a try/catch around each separate action. All my database activity is inside wrapper methods, where I check for and log errors.

What happens if TextOutputStream.Close raises an exception?

Ideally, TextOutputStream.Close would be implemented such that it doesn’t throw exceptions since it is supposed to free resources. I don’t know if that’s how it’s implemented in Xojo, however. If Close does have the possibility of raising exceptions, it would potentially lead to memory leaks.

A nice feature in the documentation for Xojo would be documentation of all possible exceptions for each method.

Finally is used for code that needs to run even if an exception occurred earlier in the method. For example, when using a Semaphore:

Dim lock As New Semaphore
lock.Signal() 
Try
    // do things that might raise an exception
Finally
    lock.Release()
End Try

Without a Try...Finally construct, exceptions raised after the Semaphore is signaled would prevent it from ever being released, and any other threads that are waiting on the Semaphore would deadlock.

1 Like

This is the problem with Exceptions - you don’t know what can throw one.

Documenting them would be a start but even that isn’t a very good solution as what can throw an exception or the exceptions thrown could change between versions.

A much better solution would be if there were some kind of Checked Exceptions implementation that at least got the compiler to throw warnings if exceptions were not being handled.

There is indeed a feature request for this <https://xojo.com/issue/55873>

I know, but that would involve Xojo implementing features that users want rather than features they think users want.

3 Likes

I agree whole-heartily. Checked exceptions get a lot of grief in Java, but I’m a fan of them for this very reason.

Not any more. It will throw the IOException instead of returning Nil.

1 Like

Following the design logic that you are all sharing and testing, this is what I’ve settled on:

If f <> Nil And Not f.Exists Then
  Try
    theTOS = TextOutputStream.Create(f)
    If defaultEntry <> "" Then
      theTOS.Write defaultEntry + EndOfLine.UNIX
    Else
      theTOS.Write "" + EndOfLine
    End If
    theTOS.Flush
  Catch e As IOException
    // Permissions issue?
  Finally
    theTOS.Close
  End Try
End If

If theTOS is nil at the Create line, the Finally block also gets executed (as it’s always executed whether you got an exception or not) and theTOS.Close raises a NilObjectException, this time, unhandled.
Check if it’s nil and you’re set.

1 Like

Thanks, Arnaud!

If f <> Nil And Not f.Exists Then
  Try
    theTOS = TextOutputStream.Create(f)
    If defaultEntry <> "" Then
      theTOS.Write defaultEntry + EndOfLine.UNIX
    Else
      theTOS.Write "" + EndOfLine
    End If
    theTOS.Flush
  Catch e As IOException
    // Permissions issue?
  Finally
    If theTOS <> Nil Then
      theTOS.Close
    End If
  End Try
End If
1 Like

You’re welcome :wink: