There have been some similar questions posed here but none seem to answer my following question. I have a function with a menu inside the function. This function is embedded within a main function. If the user hits "Quit" on the menu gui, I want the function to stop on that line and not continue AND I want the main function to stop as well.
But the function also has variable outputs, so I always get the error: "Output arguments {var} not assigned during call to {function}"
I have tried using "return", "break" or others, but have not seen a simple solution to this problem. Any ideas are appreciated.
function main
%do stuff
function [a,b,c,d]=sub_main
imenu=menu(' ','yes','no','quit');
if imenu==3
%RETURN, BREAK OR SOMETHING!
end
a=1; b=2; c=3; d=4;
end
end
Related
My matlab program is a multiple window programmatic GUI. I have implemented a reporting system so when an error is encountered, it calls a function I wrote, generateReport.m, which sends an e-mail with some log and state info and then continues execution.
To accomplish this I have put a try-catch block in EVERY single function. That means even creating a wrapper for my main function. Does anybody know of a way to avoid this? I.e. being able to but a global try-catch. The reason I need multiple try-catch blocks right now is because try-catch will catch errors in functions within the block, but not sub-functions of those
Example psuedo-code:
try:
segmentImage
catch:
generateReport
end
^-- This way an error in segment-image calls generateReport, however an error in a subfunction of segment-image won't. Optimally I would only need one try-catch (or some other statement/structure I'm not aware of) in each file.
Most of the files code one GUI window each. Some are just utility.
I wrote a similar question before: matlab can't catch error in subfunction
That question asked how to use the try-catch or some function-wrapper in a callback, to implement the reporting system I have now. Before I just wanted to know why I couldn't catch errors in subfunctions. I put try-catches in every subfunction to solve that.
This question is different as I'm asking is if there's another way to do this instead of putting a try-catch in every function and subfunction which is really inconvenient and doesn't look that great. Maybe a technique I don't know about to do this or a more efficient way of structuring my code to accomplish this is needed?
Example of multiple try-catches:
First the main function I run, which just wraps CSTMainWindow
function CeleST
try
% Global try-catch on CeleST
CSTMainWindow()
catch exception
generateReport(exception)
end
Within CSTMainWindow: I have to put try-catch blocks on it's subfunctions. In this example given CSTProcessVideos and CSTCheckResults are programmatic GUI files
function processVideo(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTProcessVideos
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
function checkResults(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTCheckResults
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
I would like to know if there's something I could do to avoid putting a try-catch on everything (I also put the try-catch blocks on subfunctions that don't contain code written in other files)
I hope my question was clear. Thanks in advance for the help
Preliminaries. Since your application is event-driven (i.e. performs actions by callbacks) you have at least two potential sources of errors: 1) the function that builds your GUI, and then exits, 2) every callback assigned to the active UI elements.
The GUI builder. Errors in building the GUI should exit the application. Which means that your function should look like
function main(arg1, arg2, ...)
try
% test your arguments
% create the main window
% add ui elements
% register the callbacks
% create backup for application state
catch ME
generateReport(ME);
end;
end
without putting a try/catch in every helper function that is called. Since the GUI creation is faulty, the catch block should not attempt to restore the application to a (safe) default state, because there is no such default state to begin with.
The callbacks. Errors in callbacks are most likely due to wrong user input, so there is a way to rollback the application to the last known safe state:
function ui1_cbk(h, varargin)
try
% test your arguments
% perform required action
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
function ui2_cbk(h, varargin)
try
% ...
catch ME
% ...
end;
end;
Please note that, for UI elements that have a single callback registered to them, there is one easy way to handle all actions in a single function, thus having a single try/catch block:
function ui_general_cbk(h, varargin)
try
switch get(h, 'Tag')
case 'Tag_ui1'
% test your arguments
% perform required action
case 'Tag_ui2'
% test your arguments
% perform required action
% ...
otherwise
% ignore request
end;
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
Of course, for this to work, your GUI builder should assign unique (and maybe suggestive) tags to all your active UI elements.
How to generate error reports. The try/catch block could be only at the top level of the main function and the callback; to see what exactly caused the exception, one can always inspect the .stack struct array of the ME object, and—for fancy exception handling—eventually the .cause field (which would be another MException object if not empty). Like this one avoids polluting all the functions with exception handling on every level.
Someone on /r/matlab asked me a really interesting question a few days ago related to a Flappy Bird clone submitted to the MATLAB FEX. The poster noticed that if you open the main .m file, stop it in the debugger on the first line, and run a whos(), you see a bunch of variables before they are explicitly defined by the function.
The first thing that I noticed in the editor was the syntax highlighting indicating the presence of nested functions. At a glance, it seems like the variables returned by the whos() are only those that will be defined at some point in the scope of the base function.
You can recreate this with a simpler example:
function testcode
asdf = 1;
function testing
ghfj = 2;
end
end
If you set a breakpoint on the first line and run a whos(), you get
Name Size Bytes Class Attributes
ans 0x0 0 (unassigned)
asdf 0x0 0 (unassigned)
I couldn't seem to find anything explaining this behavior in the documentation for nested functions or related topics. I am not a computer scientist and my programming knowledge is limited to MATLAB and a very small sprinkling of Python. Can anybody explain what is going on? Does it have something to do with how MATLAB compiles the code at run time?
The workspace of a function with nested function is protected. When the function is called, Matlab has to analyze the code to determine which variables are in scope at what part of the function. Remember, variables that are declared in the main function and that are used in a nested function are passed by reference, and can be modified within the nested function even if not explicitly declared as input or output.
To avoid messing up any of the nested functions, and possibly to help speed things up, Matlab does not allow assigning any additional variables to the workspace of that function. For example, if you stop the execution of the code at line 1, and then try assigning a value to a new variable klmn, Matlab will throw an error. This can be a bit frustrating for debugging, but you can always assign ans, fortunately.
I have a compiled matlab program that automatically tunes machine parameters. At the end of a tuning cycle I need to reistate some original settings. Sometime unexpected errors occur and sometimes the user can see that tuning algorithm is not working properly so should be terminated (with control-C).
If a predictable error occurs, I can reinstate parameters with a try catch block. However, if an unexpected error occurs or the user invokes control-C, the program exits without passing though the catch clause and the machine is left in an undefined state.
I know I can register a cleanup function that will run as my working functions finish, either normally, via an predictable or unpredictable error, or control-C event. Ideally, the the clean up function would do nothing and pass control to the top level to clean up if a predictable error occurs. If a control-C event or an unpredictable error occurs, clean up function should warn the user that the program failed so they clean up manually.
To do this, I need to make the fact of a predicted or not-predicted termination (i.e. control-C) known to the clean up function at run time. I know that the cleanup function takes a copy of parameter values when it is registered, and that these cannot be changed at run time, so passing in a parameter cannot work. What I believe should work is nesting the cleanup function within my working function so local variables in the enclosing function are available to the clean up function. This however does not work.
My question is: can anyone see a way to make just a single boolean available to a clean function so it can select between normal and abnormal clean up?
Here is some contrived example code that I believe should work.
function do_tuning
% Set this false to cause a warning messages for control-C or MATLAB coding errors.
normalTermination = false;
oc = onCleanup(#() my_clean_up());
tuningError = tuning_function()
if tuningError
% Set this true to suppress the warning message if a predictable error occurs.
normalTermination = true;
error('tuningError')
end
% Set this true to suppress the warning message if the function runs to completion.
normalTermination = true;
function my_clean_up
if ~normalTermination
disp('Warning: clean up failed. Please clean up manually');
end
end
end
Running real code following this pattern causes the error:
Undefined function or variable "normalTermination".
The onCleanup object calls the function from outside the workspace of the do_tuning function so using a nested function will not help...
Infact the documetation states:
Your cleanup routine should never rely on variables that are defined outside of that routine
[edit - based on comments] A better solution would be to change the problem and have all cleaning up done within the my_clean_up function, which may require it to determine if what needs doing (or to have generic behaviour which can always be applied)
If we disregard this warning and solve the question...
Passing varables between workspaces is easiest with global variables so for the example code above.
Firstly define the variable as global before initially setting it to false (otherwise the variable may be overwritten)
function do_tuning
%# snip
global normalTermination
normalTermination = false;
%# snip
Secondly define the variable as global in the my_clean_up callback function before using it to retrieve the value
function my_clean_up
global normalTermination
if ~normalTermination
%# snip
Warning as ever with global variables this is susceptible to the value of the global variable being edited elsewhere at the wrong time.
Here is a modification of my example that behaves as I want, using the global suggested by #RTL.
function do_tuning
global normalTermination;
% Set this false to cause a warning messages for control-C or MATLAB coding errors.
normalTermination = false;
oc = onCleanup(#() my_clean_up());
tuningError = tuning_function()
if tuningError
% Set this true to suppress the warning message if a predictable error occurs.
normalTermination = true;
error('tuningError')
end
% Set this true to suppress the warning message if the function runs to completion.
normalTermination = true;
function my_clean_up
if ~normalTermination
disp('Warning: clean up failed. Please clean up manually');
else
disp('Normal termination, you can relax.');
end
end
end
A more elegant solution can be achieved by modifying the onCleanup code. You could easily add a property or method to cancel the normal behaviour. Example:
classdef onCleanupCancel < handle
properties
active = true;
end
properties(SetAccess = 'private', GetAccess = 'public', Transient)
task = #nop;
end
methods
function h = onCleanupCancel(functionHandle)
h.task = functionHandle;
end
function delete(h)
if h.active
h.task();
end
end
end
end
function nop
end
At the last line of your function set the active of the onCleanupCancel object to false...
I have a problem that I'm having a hard time even framing for this question's title.
I have a library that calculates the properties of refrigerants. For example, you give pressure and enthalpy, and it tells you the temperature. That library is coded in Fortran with a mex file to interface with Matlab. Now, I am 100% sure that library is thoroughly debugged (it was coded by people much smarter than me, and has been used for almost a decade). The problem is definitely in how I call it.
And that problem is this. I call the library from a StartFcn callback (a .m script file) in a subsystem of a simulink model. The first time I run this model, it runs perfectly. The values I'm sedning to the function are therefore correct. The second time I run it, however, it crashes. The inputs both times are exactly the same.
Also, if I do a clear all between the two runs, then there is no crash. But if I do only clearvars or clear, I still get a crash. When I debug and look at the variables being passed in the function call, they are valid and the same both times.
Does someone have any experience with this, or can advise me on what I might be doing wrong? Is there something persisting within the function call that only clear all can remove and not clear? Save My Soul!
Yes, persistent variables can be declared by the persistent keyword.
If you want to clear only those, try
clear StartFcn
to clear all variables of the function StartFcn. A quote from the documentation:
If name is a function name, then clear name reinitializes any persistent variables in the function.
A quick thing to try would be clear mex inbetween simulations - this should clear all the mex code from matlab.
Other questions to think about..
Can you call the fortran interface directly from the matlab command line two times in a row?
I believe that using a m-file sfunction to call fortran in simulink is quite inefficient. Possibly consider writing your own fortran or C sfunction to interface to the code and compile in directly?
in case you're using LoadLibrary to load fortran code compiled into a dll, are you calling FreeLibrary in the mdlTerminate function?
Hope some of this helps.
I would try to put a clear all inside the function that you are calling in the StartFcn Callback.
So let's say your function is:
function [out] = nameoffunction(a,b,c)
%do calculation with a,b,c
d = a + b + c;
%output out
out = d;
assignin('base','out',d)
clear all
And you can call the function:
nameoffunction(a,b,c)
Let me know if it changes something. If this works, you could try other clear command but inside the function.
I have a Simulink model that calls a script in the InitFcn of the Model callbacks. This script initializes a bunch of variables in the base workspace so that they can be used by the Simulink model. When using Classes, I found that using the load_system function will make Matlab crash and the open_system function will work just fine.
Here the Class:
classdef simulinkModel
properties
model = '';
end
methods
function obj = simulinkModel(modelName)
obj.model = modelName;
end
function openModel(obj)
% Make sure any previously open model are closed, and open the model.
if bdIsLoaded(obj.model)
obj.closeModel()
end
%load_system(obj.model) % Matlab crash
open_system(obj.model) % Matlab run the model correctly
end
function closeModel(obj)
close_system(obj.model, 0)
end
function runModel(obj)
sim(obj.model)
end
end
end
And in the command window:
objModel = simulinkModel('test');
objModel.openModel
objModel.runModel
So how comes it crashs with the load_system vs the open_system? Is there something that the open_system function do with the base workspace that the load_system function doesn't do?
EDIT
I decided to try running simple commands outside of the class to see if the problem is elsewhere. So typing in the command window:
load_system('test')
sim('test')
When executing this in the command window, Matlab will also crash. So I'm starting to wonder if the model callbacks are not executed when the load_system function is called.
I can confirm there is indeed very different behaviour between load_system and open_system. I am currently debugging a weird problem under 2015b to be, and I just realized the LoadFcn callback of my simulink models is not called when I use load_system, but is is called properly when I use open_system. I don't know that this is documented anywhere. I find this callback name misleading if it is not called when you "load" the system !!! If I find more info, I will post back on this thread.