Errors in listener callbacks

28 views (last 30 days)
Nathan Bblanc
Nathan Bblanc on 30 May 2023
Edited: Nathan Bblanc on 18 Feb 2024
I have an app built in MATLAB App Designer. the underlying code utlizes events and listeners. my problem is this: Whenever an error occurs in the code, the app needs to know about this. when the error occurs in the code itself, there are built in "catch" commands that notify the GUI.
However, when an error occurs in one of the listener callbacks, there is some built in mechanism that replaces the error with a warning. Instead of getting an error message we get a warning: "error occurred during execution of listener callback" and a description of the error message.
Is there a way to cancel this mechanism? to let the errors in listener callbacks become actual error messages? or maybe a way to notify the app in case of a warning? something like try catch that includes warnings?
many thanks
Nathan

Accepted Answer

Adam Danz
Adam Danz on 31 May 2023
Edited: Adam Danz on 31 May 2023
> Is there a way to cancel this mechanism? to let the errors in listener callbacks become actual error messages?
No, there isn't an off-switch to this behavior.
> or maybe a way to notify the app in case of a warning?
It's unclear what listeners you are refering to but I'll assume they were added by the developer of the app rather than by app-designer. One idea is to wrap the listener's callback function within a try/catch and to take some action within the catch block when there is an error. However, warnings are not caught by the try-block.
Another idea is to use lastwarn to clear the last-warning-history at the beginning of the listener's callback and then to query lastwarn again at the end of the callback to determine if a warning was thrown.
Neither of these potential solutions would catch warnings that are thrown prior to or after reaching the callback function.
lastwarn('') % clear last warning
% < function code goes here >
[msg, id] = lastwarn();
if ~isempty(msg)
% take action on warning
end
  5 Comments
Adam Danz
Adam Danz on 18 Feb 2024
I get where you're coming from, and I can see how this behavoir might feel like a head-scratcher. "Why" questions about long-established decisions can be tough to address. While I can't shed light on the historical 'why' behind this particular design choice, I could offer suggestions.
> we can decide if the "single faulty listener" should "disrupt the entire system" or not
I'm not sure that I follow this argument without a clarifying use case example. Listener callbacks have their own workspace so even if a listener callback would throw an error it wouldn't affect or disrupt any processes outside of that workspace. When there is an error within a listener callback, execution stops at that line which is a disruption to the processes within that workspace.
Try/catch statements still function within listener callbacks, although they can't be used to rethrow an error. They are still an effective way to detect and react to errors within the listener callback.
Here's an example.
I've created a faulty listener that updates the color of a marker any time the axes limit change. However, the marker no longer exists which causes an invalid or deleted object error in the listener callback.
I've caught the error and displayed the error message as red text along with a beep to simulate a MATLAB error.
Run this from a script and then manually drag the axes. Make sure your speakers are on.
figure
ax = axes;
h = plot(.5,.5,'+','MarkerSize',40,'LineWidth',5);
addlistener(ax, {'XLim', 'YLim'}, 'PostSet', @(~,~)listenerFcn(h));
delete(h)
function listenerFcn(h)
% Responds to changes to axis limits
try
h.Color = rand(1,3);
catch ME
% Simulate error
beep
fprintf(2,[ME.message,newline])
end
end
You'll see a burst of successive beeps along with a stack of error messages.
Nathan Bblanc
Nathan Bblanc on 18 Feb 2024
Edited: Nathan Bblanc on 18 Feb 2024
Hi Adam, thanks for your patience in answering here. I have moved past this issue a while ago, but since the discussion was rekindeled, I can try and explain why this mechanism was so problematic for me, why the solution you offered is not ideal, and what I ended up doing. In a nutshell- because of this mechanism, I can't trust any of my "try/catch" commands to actually catch errors. However this can be solved by using a specific class aimed at catching errors and handling them.
Original Problem:
To simplify Things, let's say I have a class of objects called "blob.m" with a property "blobidy" that is restricted to be less than 10. A blob can "adopt" another blob, leading to a constant ratio of 2 between their blobidies. (meaning, the father always has twice the blobidy of the son) this is achieved by adding postset listeners to the blobidy property of both blobs. see attached file "blob.m".
My problem can be seen in "Original _Script.m". When I try to change the father's blobidy to 12 ,the error is caught, a dialogue box is displayed, an error counter is updated and the blobidies are restored to their original values. However when I try to change the son's blobidy to 6 (indirectly trying to change the father blobidy to 12 again), the error is not caught, the counter is not updated and the original values are not restored.
Adam's Suggestion:
Following Adam's suggestion, I can add a try-catch inside the post-set callback itself. see "blob_adam.m". However, this doesn't help me a lot as can be seen in "Adam_Suggestion.m". I can display the dialogue box, but I cannot update the error counter or restore the values, because the "Catch" occurs in a different workspace. I assume there are several workarounds for this, and here is the one I chose.
My workaround
My workaround, that worked pretty well even in the original, more complex problem, is this: I introduce a new class called "Global_Blob_King.m" that is in charge of the blob kingdom. Each blob knows its blob king (has a property "king"), and notifies it in case of an error. see "blob_workaround.m". The king is in charge of the error counter, and also in charge of saving and restoring the original values. as can be seen in "My_Workaround.m", this actually works.

Sign in to comment.

More Answers (0)

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!