2

My Question: Given a function handle, does matlab parse the string each time it needs to evaluate it, or just once and then it caches it?

Example

Consider the ingenious function

function [] = foo(func)
for j=1:1e4
    func(j);
end

and the script

func1 = @(x) 5*abs(x)^2
function foo(func1);

At run-time, Matlab needs to interpret @(x) 5*abs(x)^2 as a function. In this example, does it do it once, or a thousand times?

Amir Sagiv
  • 376
  • 5
  • 23

1 Answers1

6

First of all @(x)cos(x) is not a string, it is an anonymous function declaration. When you create an anonymous function, MATLAB essentially creates a function object which contains all of the information it needs to run. This anonymous function can then be passed around to various functions or even saved to a file. As such, it is only constructed once and evaluated many times.

When evaluated, MATLAB does not do any caching, so calling the same anonymous function with the same inputs many times causes the contents of the anonymous function to be evaluated each time.

If you want to get more information about your anonymous function, including the local workspace of the function, you can use the functions function

f = @(x)cos(x);

functions(f)

%            function: '@(x)cos(x)'
%                type: 'anonymous'
%                file: ''
%           workspace: {[1x1 struct]}
%    within_file_path: '__base_function'

That being said, in your example, it could really be reduced to a function handle rather than an anonymous function since you pass all input arguments directly to cos without modifying them. As you can see, this has a different internal representation and from some preliminary benchmarks, it seems to be marginally faster.

f = @cos

functions(f)

%    function: 'cos'
%        type: 'simple'
%        file: ''

And a quick benchmark

function benchit
    fprintf('Anonymous function: %0.4f\n', timeit(@option1));
    fprintf('Function handle:    %0.4f\n', timeit(@option2));
end

function option2()
    f = @(x)cos(x);
    for k = 1:10000
        f(k);
    end
end

function option1()
    f = @cos;
    for k = 1:10000
        f(k);
    end
end

And the results (not really a huge difference)

Anonymous function: 0.0056
Function handle:    0.0049

A few more things

  • When creating the anonymous function, the anonymous function declaration must still adhere to all of MATLAB's standard syntax rules otherwise it won't be created. For example, the following would throw an error during anonymous function creation since it is invalid syntax

    func = @(x)thing]
    

    Error: Unbalanced or unexpected parenthesis or bracket.

  • When you evaluate an anonymous function (after it's successful creation), it's just like evaluating any other function in that the anonymous function can throw an error and the error depends upon the input.

    func = @(x) x + [1 2];
    
    func([3 4])
    %   4   6
    
    % Now we're going to pass an array that isn't 1 x 2
    func([5 6 7])
    

    Matrix dimensions must agree.
    Error in @(x)x+[1,2]

Suever
  • 64,497
  • 14
  • 82
  • 101
  • 2
    `functions` is documented: [https://www.mathworks.com/help/matlab/ref/functions.html](https://www.mathworks.com/help/matlab/ref/functions.html) – it is however only recommended for debugging. – horchler Jan 25 '17 at 22:29
  • @horchler Welp, not sure why I was thinking that. Updated. Thanks. – Suever Jan 25 '17 at 22:30
  • @Suever thanks. Couple of follow ups. (a) I see why cosine is a bad example, I'll give one that really requires anonymous function. (b) A lot of times an anonymous function is created, but only when you try to evaluate or execute it, it throws an exception that this is not valid. Try to define `func2 = (x) dfadf9x)`. So, what kind of function does it store for `func2`? – Amir Sagiv Jan 25 '17 at 22:34
  • @AmirSagiv Whether it's a function handle or an anonymous function, it doesn't matter. It's still created once and evaluated many times. An *error* when evaluating it is in the *evaluating part* of the above statement so an error can occur each time you evaluate it. – Suever Jan 25 '17 at 22:41
  • @AmirSagiv Also `func2 = (x)dfadf9x)` doesn't define *anything* because it's not a valid anonymous function definition and it will fail due to a syntax error. – Suever Jan 25 '17 at 22:43
  • @Suever of course it's not valid. My point is that when I define an anonymous function, it doesn't check that my definition bears any meaning or sense. It only checks what I've written in the evaluation side. – Amir Sagiv Jan 25 '17 at 22:49
  • 1
    @AmirSagiv See my updates above. As far as errors, issues, etc. it's literally no different from a function file (the "correctness" isn't known until it's passed variables), it's just that it's defined inline. – Suever Jan 25 '17 at 22:49
  • @AmirSagiv I'm not sure what you're confused about. As I've restated many times. It's *created* once and *evaluated* many times. Each evaluation can throw it's own errors because it's evaluated with *whatever inputs you pass it that particular time*. I'm not sure how you would expect it to behave any different. – Suever Jan 25 '17 at 22:53
  • Yes, I see now in your response. It makes total sense, thanks. – Amir Sagiv Jan 25 '17 at 22:56
  • @AmirSagiv if this answered your question consider marking it as a solution – Suever Jan 26 '17 at 11:56
  • @Suever , I still have a problem with run-times. In my codes it seems that using a function is much more slow then hard-coding this function into the code. Is this because it's a function (anonymous or not)? – Amir Sagiv Jan 26 '17 at 13:45
  • 1
    @AmirSagiv Did you benchmark it by writing the function in a `.m` file and comparing? There is overhead when calling a function (anonymous or otherwise) as opposed to writing it directly into your code. – Suever Jan 26 '17 at 13:47
  • Ok, finally I've found the performance issue, which had nothing to do with the anonymous function mechanism. Still, I learnt a lot. Thanks! – Amir Sagiv Jan 28 '17 at 11:49