You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to obtain an MException in a cleanup function
4 views (last 30 days)
Show older comments
Hi all,
I've noticed that "lasterror" indicates that it will be obsolete soon, and MException.last indications that it can only be used from the command line. Without using a try/catch construct in the calling/parent function that is being cleaned up, is there any good way to check to see if the calling function being cleaned up generated an error?
14 Comments
Adam Danz
on 26 Oct 2020
Wouldn't the dbstack or the 'stack' field of the MException list what you're looking for?
Matt
on 26 Oct 2020
Hi Adam,
The question here is how to obtain the last MException now that lasterror is being obsoleted. Once it is obtained, yes, the stack field is very useful.
Bruno Luong
on 26 Oct 2020
TMW recommends using try/catch to get the error. What is the reason to prevent you to follow their recommendation?
Matt
on 26 Oct 2020
Hi Bruno,
- TMW also recommends onCleanup for error handling. Having to do a try catch as well as onCleanup is undesirable. In this case no error handling is being done beyond logging.
- Specifically try/catch and rethrows change how the debugger handles exceptions in undesirable ways. If there was a good way to use dbstop if caught error, this wouldn't be as necessary, but given its current unusablility finding a workaround without try/catch is important.
This is way beyond the scope of the question, but if there was a way to limit dbstop if caught error to non-built in functions, it would be much more useful. Currently if I set it, I get a caught exception within one second of setting it without even running any code. Something about device plugins in a toolbox library. But even when it behaves "normally", there are too many exceptions in the built in libraries to use dbstop if caught error without a lot of constant frustration/time waste.
Bruno Luong
on 26 Oct 2020
Edited: Bruno Luong
on 26 Oct 2020
"Having to do a try catch as well as onCleanup is undesirable"
Why?
I never though they usage must be exclusive. In fact they do different things. I usually use them like this:
- onCleanup performs clean-up tasks, usulally implemented in the calling function, it implements the tasks that must be carried-out where as the function terminates normally or terminates because of and error; and
- try/catch is on the caller, to ignore/log/display a warning message if error occurs in the calling function, and eventually branch to different part of the code.
So I never wonder for onCleanup to knows whereas error occurs and what kind of error. That's the job of try/catch.
Now if you don't wan't to use both, then I would say, too bad for you to limit yourself with such constraint.
DBSTOP is for debugging, this is another topic in my book. I'm not sure I understand your description of the inconvenient of debugging flow and exception handling in regular flow of the code.
Rik
on 26 Oct 2020
I'm a bit concerned about the removal of lasterror. I want my code to be compatible with Matlab 6.5 (R13), because it is lightning fast in some situations. If lasterror is removed I will be forced to use this mess:
ME='initialise ME as char';
try
something_that_may_error
catch ME; %#ok<NOSEL>
% ^ suppress output in case of ML6.5 (and add the %#ok pragma for mlint)
if isa(ME,'char'),ME=lasterror;end %#ok<LERR>
end
Adam Danz
on 26 Oct 2020
Edited: Adam Danz
on 26 Oct 2020
Using onCleanup will not prevent the error from being thrown.
For example,
cleanup = onCleanup(@()disp(dbstack()));
t = 5 * randi(100);
z = t+x; % x is not defined; hence, error.
Unrecognized function or variable 'x'.
So it's still not clear to me what the use case is here.
Matt
on 26 Oct 2020
@Bruno,
Its not just aesthetics. Try/Catch changes the debuggers behavior, so if you don't want to do that (debugger behavior can be fairly important in some frameworks for executing other code), but still want to detect that an error occured, then lasterror has a distinct and useful purpose.
Bruno Luong
on 26 Oct 2020
Edited: Bruno Luong
on 26 Oct 2020
try
dosomebuggycode
catch ME
rethrow(ME) % <- here you have you error code, and debugger stops here is wished
% you can also comment temporary try/catch during debugging
% please explain why it doesn't fit your need???
% how lasterror() can help you more than this???
end
Matt
on 27 Oct 2020
Edited: Matt
on 27 Oct 2020
Here's some pseudocode with an example demonstrating the utility of lasterror to maintaining a natural debug environment.
function myNiceFunction(usersBuggyFunctionHandle)
onCleanup(@myNiceOnCleanup)
%Do Some setup
outputData = usersBuggyFunctionHandle() %<--- User needs to be able to natively debug this with dbstop if error
%onCleanup currently lets me log errorData here - without a try catch
end
function myNiceOnCleanup
logErrorData(lasterror) %<--- On Cleanup log the error data if its available
end
Steven Lord
on 27 Oct 2020
In the pattern you describe, a try / catch block would be my choice of approaches to use. You only want to log the error data if an error actually occurs and you only want to log the error if it comes from the scope of your function. As written your myNiceOnCleanup function will always get executed, error or no error. In addition there's a chance (albeit a slim one) it could catch an error from a timer object's TimerFcn, a Handle Graphics callback function, etc. [I'm not sure offhand how or if lasterror interacts with a parallel.ThreadPool but I wouldn't be surprised if "complicated" appears more than once in the answer.]
function myNiceFunction(usersBuggyFunctionHandle)
%Do Some setup
try
outputData = usersBuggyFunctionHandle();
%<--- User needs to be able to natively debug this with dbstop if error
catch errorData
myNiceOnCleanup(errorData)
end
end
function myNiceOnCleanup(errorData)
% Process the MException
logErrorData(errorData)
rethrow(errorData) % or throwAsCaller
end
As for debugging this, if an error occurs the user can set a breakpoint on the line inside the catch where myNiceOnCleanup is called. Or maybe this function accepts an optional input and you have a section in your code that calls keyboard if it is specified.
Matt
on 27 Oct 2020
Thanks Steven, and everyone else for all the input. It is much appreciated.
I understand the try/catch approach. The issue is that the try/catch approach takes twice as long to debug because to debug it you have to run it twice - once to find out its going to crash, and once with a debug point in. When you have code that takes hours to execute, this is a non-starter.
Long story short, try/catch is not useable for this usecase. When lasterror is obsoleted, I'll probably need to remove the error logging rather than doubling the amount of time it takes to do debugging. This question was aimed at finding a way to not do that.
Steven Lord
on 27 Oct 2020
If you want to unconditionally stop in the catch block, add a call to keyboard.
Matt
on 28 Oct 2020
Edited: Matt
on 28 Oct 2020
Hi Steven, the two needed behaviors (in order of importance) are
1) To unconditionally stop where a crash occurs (or at least in the same workspace), when the crash occurs, the first time the crash occurs. This is doable with dbstop if error if there isn't a try/catch statement. Try catch doesn't support it.*
2) Log exceptions when they occur. Currently the lasterror function allows a flawed but useable implementation of this.
*Try catch doesn't support this because keyboards or rethrows will cause the debugger to stop in the workspace where the try/catch block is, not where the exception originally occured in the users code. dbstop if caught error does nominally supports this, but as I mentioned above its really not useable in its current state because it catches exceptions in the try/catch blocks in built in code.
Answers (0)
See Also
Categories
Find more on Performance and Memory in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)