[Gambas-user] Error Management

Tobias Boege taboege at gmail.com
Tue Mar 26 22:41:35 CET 2019


On Mon, 25 Mar 2019, T Lee Davidson wrote:
> Here is an example use case of Error.Propagate().
> 
> I try to, at least loosely, follow the MVC (Model/View/Controller) design
> principles. The View is my Form and the Controller is the Form code. The
> Model is the business logic that is usually, for me, contained in multiple
> Classes/Modules that could call subroutines in other modules handling such
> services as data access and web interfaces.
> 
> If an error occurs within the Model business logic, I may want to pop up a
> Message box for user intervention. But, I do not want the Model to handle
> what should be done in the View. I want the View, through the Controller, to
> handle that.
> 
> An error in the Model will not bubble up through the subroutine stack
> automatically and, if not handled, would cause the application to panic at
> the location of the error. Using Error.Propagate() allows me to pass the
> error condition up through to the Controller so it can present the user with
> a Message.Error() in the View.
> 

Very good, or at least it plays into my hands :-) That's exactly the
layering of responsibilities that I've been propagating to Hans in our
recent discussions of error management, I just didn't think about it
as MVC.

One thing I have to object to is the half-sentence

> An error in the Model will not bubble up through the subroutine stack
> automatically [...]

because it will. When an error is raised, Gambas stops execution of the
current frame and looks for error handlers -- Try, Catch or Finally.
If it can't find them, it walks up the call stack and successively looks
for error handlers there, until it reaches the global level where you
can have a Static Public Sub Application_Error() in the startup class.
If the error wasn't handled, the interpreter prints it and exits.

This is what you do in your example: you handle the immediate error from
ThreeSub in TwoSub -- that makes Gambas happy, it stops the stack unwinding.
You raise a new error then with Error.Propagate, making Gambas unhappy,
which is caught again one level up.

To observe the automatic stack unwinding, look at this:

  Public Sub Main()
    f()
  End

  Public Sub f()
    Try g()
    If Error Then Print Error.Backtrace.Join("\n")
  End

  Public Sub g()
    h(3)
    Print "error from h will jump over this"

    Finally
      Print "passing through g"
      Error.Propagate() ' Finally handles an error, apparently
  End

  Public Sub h(x As Integer)
    Print 1 / x
    h(x - 1)
    Print "execution of h stops before we're here!"
  End

  > 0.333333333333333
  > 0.5
  > 1
  > passing through g
  > Main.h.22
  > Main.h.23
  > Main.h.23
  > Main.h.23
  > Main.g.13
  > Main.f.8
  > Main.Main.4

> If at one point in the subroutine stack I handle the error, then I should
> use Error.Clear() to prevent a false positive when testing for an error
> condition further up in the stack.
> 

That's a very good point that I wasn't aware of. You could say that Try-,
Catch- of Finally-ing an error puts the interpreter out of emergency mode,
it will stop unwinding the stack and continue normal execution. But if
you have multiple "If Error Then"s on your code paths, you *have* to
Error.Clear() after you handle an error, to not handle it again.

Valuable information for the chapter!

Regards,
Tobi

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk


More information about the User mailing list