Problem using str2func for creating a function handle

4 views (last 30 days)
Hello!
I have two functions:
%---------
function [ handle_res ] = handle_fun_creation_2( File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = str2func(['@' File_String]);
elseif Type_identifier == 1
handle_res = str2func(['@(t,y)' File_String '(t,y,Value)'] );
end
end
%-------------
and:
%-------------
function [ y ] = test_3( t,x,Var_opt )
y=x+Var_opt(1)+Var_opt(2);
end
%---------------
Could anyone explain me why the following code doesn't work:
%---------------------------
Var_opt = [30 40]';
[handle_4] = handle_fun_creation_2('test_3',1,Var_opt);
[t6,y6] = ode15s(handle_4,[0:1],0);
Undefined function or variable 'Value'.
Error in @(t,y)test_3(t,y,Value)
%---------
But this one does?
%---------
handle_5 = @(t,y)test_3(t,y,Var_opt);
[t7,y7] = ode15s(handle_5,[0:1],0);
I think I'm missing some detail on how str2func works maybe? Thanks in advance.

Accepted Answer

Walter Roberson
Walter Roberson on 28 Jan 2014
str2func() does not execute the content of any strings it is passed so it has no idea that the string 'Value' should relate to the parameter named Value.
if isnumeric(Value)
valstr = sprintf('%g', Value);
else
valstr = char(Value);
end
handle_res = str2func(sprintf('@(t,y)%s(t,y,%s)', File_String, valstr));
  4 Comments
Pedro
Pedro on 28 Jan 2014
Edited: Pedro on 28 Jan 2014
Not exactly, nonetheless I believe I found a solution using eval and sprintf:
%------------
function [ handle_res ] = handle_fun_creation_2(File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = sprintf('@%s',File_String);
elseif Type_identifier == 1
handle_res = sprintf('@(t,y)%s(t,y,Value)',File_String);
end
%----------------
[sprint_4] = handle_fun_creation_2('test_3',1,Var_opt);
handle_4 = eval(sprint_4);
[t6,y6] = ode15s(handle_4,[0:1],0);
%------------------
Although I'm not sure about this code's efficiency, it works. Many thanks for your input!
Stephen23
Stephen23 on 1 Jan 2022
Edited: Stephen23 on 1 Jan 2022
"Although I'm not sure about this code's efficiency, it works"
It is not efficient, nor does it work as you think it does.
For example, although you pass the input argument Value to handle_fun_creation_2 it remains totally unused, it is only when you later EVAL the string in the caller workspace that MATLAB will look for a function or variable named Value. You can easily test this by calling handle_fun_creation_2 with complete nonsense for the third input argument and everything will work (as long as the correct Value is defined in the caller workspace!):
sprint_4 = handle_fun_creation_2('test_3',1,{'hello world'}) % 3rd arg = silly cell array
sprint_4 = '@(t,y)test_3(t,y,Value)'
Value = [pi,2/3]; % <----------- must be defined in the calling workspace...
handle_4 = eval(sprint_4) % <--- because this is actually where Value is included.
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % no errors
If Value is not defined in the caller workspace then your code will not work, it will throw an error about Value being undefined (see bottom of this comment). It is clear that my silly Hello World cell array actually does nothing.
But this just seems to be a very indirect and inefficient approach to parameterize a function:
As the documentation shows, a much simpler and more efficient approach is to use an anonymous function:
fn1 = @(x,y)test_3(x,y,Value);
[t7,y7] = ode15s(fn1,0:1,0);
isequal(t6,t7)
ans = logical
1
isequal(y6,y7)
ans = logical
1
and if the function name really is provided as text (suboptimal design, but still simpler and more direct than a special "creation" function returning a string and evaluating it to get a function handle):
fns = 'test_3';
fn2 = str2func(fns);
fn3 = @(x,y)fn2(x,y,Value);
[t8,y8] = ode15s(fn3,0:1,0);
isequal(t6,t8)
ans = logical
1
isequal(y6,y8)
ans = logical
1
And finally, lets try your code when Value is not defined in the caller workspace:
clearvars Value
handle_4 = eval(sprint_4) % looks the same... but is it?
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % nope.
Unrecognized function or variable 'Value'.

Error in solution>@(t,y)test_3(t,y,Value)

Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.

Error in ode15s (line 152)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);

Sign in to comment.

More Answers (0)

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!