How to obtain an MException in a cleanup function
6 次查看(过去 30 天)
显示 更早的评论
Matt
2020-10-26
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 个评论
Adam Danz
2020-10-26
Wouldn't the dbstack or the 'stack' field of the MException list what you're looking for?
Matt
2020-10-26
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
2020-10-26
TMW recommends using try/catch to get the error. What is the reason to prevent you to follow their recommendation?
Matt
2020-10-26
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
2020-10-26
编辑:Bruno Luong
2020-10-26
"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
2020-10-26
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
2020-10-26
编辑:Adam Danz
2020-10-26
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
2020-10-26
@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
2020-10-26
编辑:Bruno Luong
2020-10-26
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
2020-10-27
编辑:Matt
2020-10-27
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
2020-10-27
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
2020-10-27
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
2020-10-27
If you want to unconditionally stop in the catch block, add a call to keyboard.
Matt
2020-10-28
编辑:Matt
2020-10-28
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.
回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Performance and Memory 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!发生错误
由于页面发生更改,无法完成操作。请重新加载页面以查看其更新后的状态。
您也可以从以下列表中选择网站:
如何获得最佳网站性能
选择中国网站(中文或英文)以获得最佳网站性能。其他 MathWorks 国家/地区网站并未针对您所在位置的访问进行优化。
美洲
- América Latina (Español)
- Canada (English)
- United States (English)
欧洲
- 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)
亚太
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)