Getting an error in a listener callback function to trigger an error in/terminate execution of the calling function
32 views (last 30 days)
I am using Matlab events to update the state of objects with time. One function is incrementing time in steps, and each step notifies all objects that time has incremented so they can update their state to the new time.
is run by the calling function, that triggers execution of the function below by listening objects:
However, if an error/exception occurs (because noone can write perfect code) in the callback function (Controller_TimeIncrementedEventHandler), the callback function will stop prematurely but the calling function will continue running and it will appear as if nothing has gone wrong in the command window/to the user. The calling function will continue to increment time and notify the listening objects. But now the result will not be correct because of an error!
I want the calling function to know of the error, so that execution can be stopped. There doesn't seem to be any way to do this, though. How do you "throw" an exception in the callback function to the calling function? I could also stop all Matlab execution (Ctrl-C) but, googling around, there doesn't seem to be any command to do the equivalent of Ctrl-C in a script. Right now I am just displaying the error in the callback function to the command window and quitting Matlab altogether to stop all execution. But this is a lousy solution (I don't want to quit Matlab, e.g. so I can see the error message, just stop the calling function from running):
Does anyone have any ideas how to stop the execution of the calling function when an error occurs in one of the listeners?
------------------- Note: the calling function continuing to execute is expected behaviour according to the help page: http://www.mathworks.com.au/help/matlab/matlab_oop/events-and-listeners--syntax-and-techniques.html
" Callback Execution
Listeners execute their callback function when notified that the event has occurred. Listeners are passive observers in the sense that errors in the execution of a listener callback does not prevent the execution of other listeners responding to the same event, or execution of the function that triggered the event.
Callback function execution continues until the function completes. If an error occurs in a callback function, execution stops and control returns to the calling function. Then any remaining listener callback functions execute."
Geoff Hayes on 17 Oct 2014
Joan - it seems that either the calling function should query the "life" of its objects (check their "heartbeat" so to speak). If the heartbeat of at least one object has stopped, then the code knows that there has been an error and so should terminate gracefully.
I suppose you could do this in a number of ways, but most would probably require that the calling function listen for events generated by the objects (whatever they are). Either they return a "still alive" event in response to the TimeIncrementedEvent. Or the objects could periodically send out a "still alive" event. And if the caller has not received one of these events over a certain period of time, then it knows that an object is dead and so should stop.
Perhaps easier is to just use your try/catch block in the listener to send an "object/listener is dead" event whenever an error is thrown from that code
% notify caller with ObjectIsDeadEvent
This way, the caller doesn't need to worry about checking responses from its objects, and would only care if it receives the ObjectIsDeadEvent.
I'm not sure how feasible this is with your code, but it may be worth a look.
Jacob Lynch August on 17 Feb 2019
I'm also having the same issue. It would be better if the error stopped execution immediately rather than continue on. For example, the following class manages properties B and C, setting them only when the user requests them. performing a disp(OBJ) would trigger an error in both B and C, whereas it would be more desireable for the execution to stop immediately when the computation in SetB(OBJ) errored.
classdef ManagedObject < handle
function OBJ = ManagedObject(INPUT_A)
OBJ.A = INPUT_A;
% these listeners are destroyed when the values for B and C are set.
OBJ.B = listener(OBJ,'B','Preget',@(~,~)SetB(OBJ));
OBJ.C = listener(OBJ,'C','Preget',@(~,~)SetC(OBJ));
% some more complicated function resulting in a nan returned
OBJ.B = nan;
% some more complicated function
OBJ.C = OBJ.B + 1;
The only way I've found for this to terminate immediately, but deceptively, is to use try-catch blocks in each function, and the catch statements concluding with delete(OBJ) and rethrow(MException). Again, it would be preferable for the listener callbacks to not issue as warnings but terminate execution immediately.