I have some error handling code that I want a bunch of functions to use, so in order to avoid repetition I thought I would put it in my generic class that holds utility functions FunctionContainer
.
Here's a truncated version of FunctionContainer
:
classdef FunctionContainer
methods (Static)
function run(func, ExpInfo, logdir, newdir, varargin)
try
func(ExpInfo, newdir, varargin)
catch ME
FunctionContainer.errproc(logdir, newdir, ME)
end
end
function errproc(logdir, newLogDir, ME)
errdir = fullfile(logdir, 'error');
movefile(newLogDir, errdir);
pathParts = strsplit(newLogDir, filesep);
logID = pathParts(end);
newLogText = fullfile(errdir, logID, 'error.txt');
fid = fopen(newLogText, 'wt');
fprintf(fid, '%s\n%s\n', ME.identifier, ME.message);
for i = 1:length(ME.stack)
fprintf(fid, '%i\t%s\n', ME.stack(i).line, ...
ME.stack(i).file);
end
fclose(fid);
rethrow(ME);
end
function newdir = prolog(logdir, id, supfiles)
id = join([id, string(clock)], '_');
newdir = fullfile(logdir, id); mkdir(newdir)
stack = dbstack('-completenames');
files = horzcat({stack.file}, supfiles);
for i = 1:numel(files)
copyfile(files{i}, newdir)
end
end
end
end
Here's the context in which I'm using it:
function realign(ExpInfo)
fc = FunctionContainer;
logdir = ExpInfo.logdir;
ws = fullfile(logdir, 'workspace.mat'); save(ws);
newdir = fc.prolog(logdir, 'realign', {ws});
fc.run(runRealign, ExpInfo, logdir, newdir);
function runRealign(ExpInfo, newdir)
% do a bunch of stuff
end
end
The relevant line in my script ks_main.m
that calls realign
is
realign(FullData)
I get this error:
8 fc.run(runRealign, ExpInfo, logdir, newdir);
Error using realign/runRealign
Too many output arguments.
Error in realign (line 8)
fc.run(runRealign, ExpInfo, logdir, newdir);
Error in ks_main (line 35)
realign(FullData)
I just don't understand this error in this context. None of these functions is returning anything or has any outputs. I could maybe understand if runRealign were getting too many inputs, and I tried defining runRealign
like this
function runRealign(ExpInfo, newdir, varargin)
but that made no difference. Maybe this has something to do with passing a function as an argument to another function? What's the right way to do this in Matlab?
CodePudding user response:
You need to put the @
symbol in front of your function argument in fc.run
. Always do this when passing a function handle as an argument (https://au.mathworks.com/help/matlab/matlab_prog/pass-a-function-to-another-function.html). Line 8 of realing.m should be:
fc.run(@runRealign, ExpInfo, logdir, newdir);
There are a couple of other issues. One is that you are missing an end
at the end of FunctionContainer
. This is probably just a typo in your question or else you would also have an error related to this.
Another small implementation detail is that you don't need to use logdir
as an argument if it is going to be a field in ExpInfo
anyway---you can simply access it from ExpInfo
inside of FunctionContainer
without having to pass it explicitly to run
. Passing both ExpInfo
and its field logdir
to the same function is unclear and stylistically bad practice. (Which reminds me, you should provide a definition of FullData
in your question as well. I had to discern that it requires this field.)
However, this is code as is is also going to cause an exception to be thrown on line 6 of FunctionContainer
. The definition of runRealign
only takes 2 arguments, but when you try
to run it in FunctionContainer
you expect 3: func(ExpInfo, newdir, varargin)
. If I change line 6 of FunctionContainer
to:
func(ExpInfo, newdir)
it works.
To make this robust and error free you need either to parse the varargin
in FunctionContainer
so that it intelligently handles a variable number of arguments (https://au.mathworks.com/help/matlab/ref/varargin.html), or else guarantee that the input function handle points to one that has 2 arguments for ever and always.