A more modern but still flexible equivalent evalin and eval?

5 views (last 30 days)
I have a requirement for a function that needs to be extremely flexible with varying data structures and output strings from the function dependent on it's usage, it is the input to ODE functions, eg.
[t, y] = ode15{whichever one}(@function_name, ...more variables);
Now I know that evalin and eval are normally considered 'evil' hence why I run it once and only once per function call as running it repetitively for multiple data within a function seems catastrophic, so is there a more modern and clean equivalent to the following Swiss army knife style of function?
function out = function_name(t, y)
% Save string of commands from workspace
commandString = char(evalin('base','commandString'));
% Process commands from commands string
eval(commandString)
end
  2 Comments
Guillaume
Guillaume on 28 Feb 2019
I'm not entirely sure which part of the code you're asking help with. In the code you show, the retrieving of commandString by evalin is unnecessary, you could just pass that as an argument to the function
As for executing any arbitrary command, you don't have a choice but to use eval. Which is fine as long as you know that this arbitrary command is not formatting your hard drive, spamming all your contacts or activating the nuclear launch codes.
If that arbitrary command is to launch an ode solver with an arbitrary function, I don't see why a handle to that function can't be passed as input to your function as well. More details are needed to understand your use case.
Jan
Jan on 28 Feb 2019
Edited: Jan on 28 Feb 2019
evalin and eval are not only "normally considered evil", but these command have shown repeatedly and consequently, that they cause more troubles than they solve.

Sign in to comment.

Answers (3)

Jan
Jan on 28 Feb 2019
Edited: Jan on 28 Feb 2019
This is an "army knife" with all tools fold out at the same time. Of course eval is powerful, but this is a drawback of this function. Asking for a "modern" metod to shoot a hole in your knee will get the same answers as using an old-fashioned way: It will still let you write code, which is hard to debug and slow at execution.
So my answer is: No, there is not less evil way to call eval.
A clean programming style reduces the dependencies between parts of the code with a "large distance" - this means especially outside the current function. Scripts and even worse strings taken by evalin from the base workspace mean, that code can affect other code, which is out of view. Then debugging a function does not allow to know, where all varaibels are coming from.
In your example:
function out = function_name(t, y)
% Save string of commands from workspace
commandString = char(evalin('base','commandString'));
% Process commands from commands string
eval(commandString)
out = t * y; % An example
end
If you read this, you cannot know if commandString contains e.g. 'clear y', which will let the code stop with an error. Even Matlab cannot know this, such that the JIT acceleration cannot improve the code, which let all functions including an eval run massively slower. We had an example with a speed factor of 100 in the forum - unfortunately I cannot find the link currently.
A programming style, which require executing remotely defined code by eval'ing a string, is flawed. You might get this to work in tiny projects with just 1000 lines of code. But if the program is useful, it is worth to expand it and to combine it with other projects. As soon as the code will have more than 100'000 lines of code, such ugly method will let the complexity explode. What happens, if you use your example of an integration in a tool for global optimization, which applies the same ugly trick of obtaining the string 'commandString' from the base workspace? This will let you run in a collision and the debugging wil be extremely hard - or impossible. I've seen too many projects fail due to a bad programming and software engineering. Billions or Euro have been burnt by the German digital police radio or the data base of the AOK health insurance. The latter ran fine in a demonstration with 100 persons, but the database access was poorly implemented and had a very bad scaling: With 100'000 persons requesting a single data set took hours already.
But coming back to your problem: Why not defining the function to be evaluated in a clean way?
Code = @() disp('hello');
fcn = @(t,y) myFcn(t, y, Code)
[t, y] = ode45(fcn, ...);
function out = myFcn(t, y, Code)
feval(Code)
out = t * y;
end
Now you do not have any remote execution of code or fragile dependencies to strings defined anywhere else. There is no danger of interferences with other software packages and the JIT acceleration works efficient. feval is very powerful also and you have still the possibliliy to cause troubles, but it is not as magic as eval.
You are not the only person who is impressed by te power of eval'ing. Many web programmers thought that this is useful also. This let the fllood of insecure web interfaces become famous for cross site scripting and SQL injections. Of course you assume that your application is not critical in the topic of security. But many other programmers shared this opinion and forgot to take into account, that their pieces of code might be used in a greater tool later.
The most important problem is not the security, but the hard debugging, the decrease of clarity and the impeding of the JIT acceleration. There is always a cleaner and more efficient way than eval. It is worth to learn the better programming style even in small projects, such that the programmer is familiar with it for productive and large projects.

Steven Lord
Steven Lord on 28 Feb 2019
It sounds like you want to turn a piece of text into a function you can evaluate. If so, consider the str2func function which will make you a function handle that the ODE solvers can accept as the first input.
Alternately if you have a symbolic expression use one or more of the functions listed in the "Ordinary Differential Equations (ODEs)" section on this documentation page or use the matlabFunction function.

Lee Gibson
Lee Gibson on 28 Feb 2019
Update: the call just using system(commandString) does work but... it works with ode15i whereas ode15s gives me an error, which I'm not finding any such error using the evalin and eval method. Investigating this further.
  1 Comment
Jan
Jan on 28 Feb 2019
If you post the original code and a copy of the error message, we can assist your investigations.
By the way, in system(commandString) there is no need to call eval or evalin, when you provide the string as parameter, see Answers: Anonymous functions for params

Sign in to comment.

Categories

Find more on Variables in Help Center and File Exchange

Products


Release

R2018a

Community Treasure Hunt

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

Start Hunting!