The Simple Case
If the functions you want to be anonymous are limited to being defined just in terms of their input parameters (like inline
functions are), and you can commit to keeping one function on your path, then you can make "sanitized" anonymous functions.
function out = sanitized_anon_fcn(str)
out = eval(str);
end
So, in your code, where you want to make an anonymous function, do this.
%testFunc2.m
function myfunc = testFunc2()
myfunc = sanitized_anon_fcn('@(x) x.^2');
end
As long as sanitized_anon_fcn.m stays on your path, you can delete testFunc2, and the saved function will continue to work. No special processing needed on save or load. Sanitized_anon_fcn
basically works like inline
but produces functions that are as fast as anonymous functions (because they are anonymous functions). The speed difference is about 10x in R2011b on my computer.
The General Case
In the general case, where the functions might actually use variables from their workspace, things get trickier.
Caveat: This is a bit of a sick hack, and I do not endorse its use in production code. But as an example of how the language works, I can't resist posting it.
I think you're 90% there already. But you need to preserve the workspace info instead of stripping it off, because it may contribute to the operation of the function. Instead of saving the anonymous function handle, grab the output of that functions()
call you're making and save that.
fcn = testFunc();
fcn_info = functions(fcn);
save willbreak.mat fcn
save blah.mat fcn_info
Then load it back. You'll still get the same warning, but now the warning applies only to function handles captured inside the workspace of your top-level anonymous function. If your function doesn't actually reference them (and it shouldn't), you can ignore the warning and it'll work.
s0 = load('willbreak.mat') % will warn and return unusable function
warning off MATLAB:dispatcher:UnresolvedFunctionHandle
s = load('blah.mat') % will warn, but the first-level function will be usable
warning on MATLAB:dispatcher:UnresolvedFunctionHandle
Then pass it to something like this function which will bring your anonymous function back from the dead in a new workspace with the same workspace values, more or less.
function out = reconstruct_anon_fcn(s)
for iWks = 1:numel(s.workspace)
wkspace = s.workspace{iWks};
varnames = fieldnames(wkspace);
for i = 1:numel(varnames)
tmp = wkspace.(varnames{i});
eval([varnames{i} ' = tmp;']);
end
end
fcn_str = s.function;
fcn = eval(fcn_str);
out = fcn;
end
In our example case:
fcn = reconstruct_anon_fcn(s.fcn_info)
fcn(2) % and it works!
Now, all the loaded anonymous functions will claim to be from this new file, but it shouldn't matter, because it's just the snapshotted state of the workspace, not closed-over variables, that is used by anonymous functions. And in the case where there were anonymous function handles in the workspace that actually were used by the computation, you'll get an appropriate error saying "Undefined function handle".
This is a hack, but maybe you could take this and extend it in to something reasonably robust.