Why can the keyword "end" be passed into a function handle in MATLAB without throwing an error?
Asked Answered
L

1

9

Consider the minimally reproducible example:

f = @(x) x
f(end)

Note, the MATLAB syntax highlighter doesn't actually highlight end in blue, showing that it is not parsing as a keyword, even though the Stack Overflow syntax highlighting does.

Output:

f =

  function_handle with value:

    @(x)x


ans =

     1

You can even do things like

f = @(x) x
a = f(end + 1)
b = f(end - 100)
c = f(2 + end)

Output:

a =

     2


b =

   -99


c =

     3

Regular Function

If you have a regular function, this doesn't work

foo(end)

function x = foo(x)
end
Error: <filename> Line: 1 Column: 5
The end operator must be used within an array index expression.

Hypothesis

From this, it appears that end is being coerced into the value 1, similar to how the boolean/logical true gets coerced to 1. My hypothesis is that since the function handle is actually a 1x1 array of function handles, the end keyword is replaced by the last valid index of the array which is 1. Since a function is not stored as an array, it doesn't work for real functions.

My Bug

I had a particularly nasty bug where I was was trying to index into an array with a similar name as a function handle:

x = 1:5
foo = @(x) x
foos = foo(x) % [1, 2, 3, 4, 5]
out = foos(1) + 2 * sum(foos(2:end-1)) + foo(end)
% Expected: out = 1 + 2 * (2 + 3 + 4) + 5 = 24, Got: out = 1 + 2 * (2 + 3 + 4) + 1 = 20

Obviously, I renamed my variables to make them more distinguishable. Still, this behavior doesn't seem useful for anything that I can think of. Is this an artifact of result of every object (including a function handle) secretly being an array? If so, is there anything the user do to prevent this or does a fix need to come from MathWorks?

Legal answered 10/9 at 8:24 Comment(3)
Looks like this has been noticed behaviour since at least 2018: uk.mathworks.com/matlabcentral/answers/…, with a similar diagnosis to yours where the interpreter recognises end as an indexing expression for a 1x1 handle before the function is evaluated. It would make sense why the same doesn't work for a separate func in that sense. Perhaps raise with MathWorks and self-answer this question with the definitive answer, since we can only guess what goes on inside the interpreterTungsten
Nice find! I see two strange things here: (a) In the expression f(1), the parentheses seem to be interpreted in two different ways: first as indexing into a 1x1 array of function handles, and then as a function call. The interpreter "should" pick only one (with the first interpretation it would return the anonymous function; with the second it would error). (b) The fact that f is a 1x1 function handle array is weird, given that it is not possible to have for example a 1x2 function handle array (it has to be a cell array of function handles)Cardinal
I just read the Matlab answers Q&A linked by Wolfie, and everything I said in my comment was already discussed there. I'll leave my comment here in case it's useful, but better go to that Q&ACardinal
M
9

There's no "secretly an array" about it - every value in MATLAB is an array. MATLAB uses the same syntax for array indexing as for function evaluation, hence the ambiguity. The behaviour is documented here: https://uk.mathworks.com/help/matlab/matlab_oop/overload-end.html

Basically, when MATLAB encounters end inside an indexing expression, it calls the end method of the thing being indexed to work out the last element in the appropriate dimension. You can implement your own end method for classes that you write - only useful if you're writing a class that is a scalar instance with array-type behaviour.

The oddness comes about because "indexing" into a function_handle actually evaluates the function. However, when interpreting the arguments to that "indexing" expression, the usual rules about evaluating the end method applies and since function_handle arrays can only ever be scalar, it always returns the value 1.

Maltzman answered 10/9 at 14:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.