Bug? Try... CallSub... Catch does not work

galimpic

Member
Licensed User
Longtime User
If an error is generated within a function called by CallSub (even in the same module), it will NOT be caught, but raised as if there were no Try...Catch block.


B4X:
Sub Activity_Resume
    Try
        CallSub("","GenerateError")
    Catch
        Log("Catch")
    End Try
End Sub

Sub GenerateError
    Dim i As Int = ""
End Sub
 

LucaMs

Expert
Licensed User
Longtime User
B4X:
Sub Activity_Resume
    If CallSub("","GenerateError") then...

' you can call GenerateError directly
     if GenerateError then...
End Sub

Sub GenerateError As Boolean ' (or: As lmException, it could be better ^_^ )
    Dim OK As Boolean = True
    Try
         Dim i As Int = ""
    Catch
         OK = False
    End Try
    Return OK
End Sub
 

galimpic

Member
Licensed User
Longtime User
@LucaMs: If I just directly call GenerateError instead of CallSub("", "GenerateError"), the error will be caught, so this is a question of CallSub behaving differently and breaking the try/catch block. Wherever the error happens in any code that executes after the try, it should be directed to the Catch part, regardles of it being in the different function. Thank you for suggesting to put another Try...Catch block in the function that I call, but, as you might imagine, this is only an example and I was not looking for that kind of workaround. I want to be able to have a whole program with maybe hundreds of functions and branches from one function and not have to make a separate try...catch in each of them, but in the one place from which everything begins.
 

LucaMs

Expert
Licensed User
Longtime User
Tried... if you call directly GenerateError, the exception will be raised, rightly, again in that routine.

(I should write: "from that routine", probably, or "by", better... someone should create an Italian programming language :D)
 

galimpic

Member
Licensed User
Longtime User
Maybe you don't understand the problem. It is not a question WHERE the exception is raised, but whether it should be CAUGHT. After the Try line, all exceptions in the code that executes before Catch line should be caught, whether they are in that function or others that get called from within that block. It works as it should if the function is called directly (the exception is caught and the execution immediately goes to the statement after the Catch), but if it is called using CallSub, and the exception is raised in that function, it is NOT caught by the Try/Catch block. You can try it with this code:

B4X:
Sub Activity_Resume
    Try
        Log("Before Call")
        'CallSub("","GenerateError")
        GenerateError
        Log("After Call")
    Catch
        Log("Caught!")
    End Try
End Sub

Sub GenerateError
    Log("Before Error")
    Dim i As Int = ""
    Log("After Error")
End Sub

If you execute this code (with call to GenerateError enabled and CallSub commented out), you will get in the Log:

Before Call
Before Error
Cought!

That looks just right (the exception is rased in the GenerateError function, but caught in the Activity_Resume, as it should). Now, comment out GenerateError call and uncomment CallSub call. The Log, after execution, is:

Before Call
Before Error
An error occured....

So, the Catch/EndTry block was NOT executed. The behaviour is different.

Here is my take on it: the CallSub maybe does not really call anything, it just puts the name of the function on the stack and lets the OS call it when it wants, so it is really detached from the linear execution of the rest of the program. But in that case, shouldn't the Activity_Resume finish first, i.e. should we not see "After Call" in the log before the line "Before Error"? If everything is executed in the same thread and, therefore, in known order, why is Try/Catch ignored? Is CallSub an exception to which Try/Catch does not apply? That is my question. If that is so and must be so, is there a method to create a program-wide place where all exceptions will be handled instead of the default behaviour of displaying it to the user and terminating the program, or putting a separate exception handler in every function that is called by CallSub?
 

DonManfred

Expert
Licensed User
Longtime User
Callsub will be executed at the end of Activity_Resume i believe. So the try cannot catch it because it will be executed after the end try.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
the CallSub maybe does not really call anything, it just puts the name of the function on the stack and lets the OS call it when it wants, so it is really detached from the linear execution of the rest of the program.
That is not correct. This is how (more or less) CallSubDelayed behaves. CallSub is called immediately (otherwise it wouldn't have return a value).

About the Try / Catch block.
Try / Catch catches error from "child subs". However when you use CallSub you are effectively raising an event and the errors from events do not propagate.
 

galimpic

Member
Licensed User
Longtime User
@DonManfred: That's what I assumed, but it is not so, as the Log file proves and Erel confirms. The CallSub, from the execution flow point of view, behaves just like any function call, except when raising exception (pun intended).

@Erel : Thank you for clarification. So, we can conclude that CallSub escapes the Try/Catch and a new Try/Catch must be placed inside every function that is being called that way, if we want to simulate the normal behaviour of the "obedient" code.
 
Last edited:

galimpic

Member
Licensed User
Longtime User
I see in Java there is "Thread.setDefaultUncaughtExceptionHandler" to catch all exceptions... is there a way to utilize that in B4A?
 

Roycefer

Well-Known Member
Licensed User
Longtime User
Thread.setDefaultUncaughtExceptionHandler will set the UncaughtExceptionHandler for the parent ThreadGroup of the calling Thread, not for the calling Thread. This new ThreadGroup-level UncaughtExceptionHandler will only be reached by an UncaughtException if the Thread in which that Exception occurred doesn't have its own UncaughtExceptionHandler installed. My investigations suggest that all B4A Threads already have UncaughtExceptionHandlers installed (this includes Threads created with the Threading library and those used by asynchronous tasks). In addition, there seems to be some other exception handling mechanism that isn't overridden by installing custom UncaughtExceptionHandlers on B4A Threads.

If you spawn new Threads using pure Java (meaning, not using B4A Threads or asynchronous mechanisms), you can install your own UncaughtExceptionHandlers for those Threads but that will probably only be of limited use to you. It's not an application-wide solution.
 
Top