5

In MATLAB R2020b I have the following code:

f=@(x) x.^2;
y=2;
g=@(x) f(x).*y

and the output is

g = function_handle with value: @(x)f(x).*y

But y = 2, so I would expect the output to be @(x)f.*2. Is this how its supposed to work or a bug? And can I display it as f.*2 rather than f.*y?

Matt Majic
  • 381
  • 9
  • 18
  • 1
    I'd say that that's how it's supposed to work, but only The MathWorks themselves can tell you why. As to chaging the display: you'd need to overload the default `disp()` method for function handle classes, i.e. you'd need to modify the MATLAB source code for this class directly. It might be impossible, e.g. if the code is pre-compiled and/or obfuscated, and even if possible, I'd recommend against modifying MATLAB source files. You might be able to write a wrapper function that's called instead on `disp()` calls for function handles. – Adriaan Jun 24 '21 at 12:07
  • 1
    Just to verify what happens to the `y`: what happens if you do `y = 3;h=@(x) f.*y` and then compare the output with that of `g`? and of course: what happens then for `g(2)` and `h(2)`? Are the outputs the same, i.e. did the value of `y` inside `g` change, or are they different? – Adriaan Jun 24 '21 at 12:19
  • Actually I meant to type g(x)=@(x)f(x).*y, as is edited. Then ```g(2)``` gives me 8 and ``h(2)`` gives 12. So it works when I put in the argument. But I need to create an array of Legendre polynomials (by recursion), ``P_=cell(1,N+1); P_{1}=@(u_) 1; P_{2}=@(u_) u_; for n=1:N, P_{n+2}=@(u_)((n+1)*@(u_)P_{n+1}(u_)-n*@(u_)P_{n}(u_))/(2*n+1); end`` and it never progresses because each cell has n but not its value in the loop. Any ideas on this? – Matt Majic Jun 24 '21 at 12:31
  • 3
    “it never progresses because each cell has n but not its value in the loop” — I think that does work, you just can’t see it from the displayed function. Evaluate them to verify. But anyway it’s much easier to represent polynomials using a vector with the constant factors, see [here](https://www.mathworks.com/help/matlab/math/create-and-evaluate-polynomials.html). – Cris Luengo Jun 24 '21 at 12:45
  • OK thanks. I actually it does output a number for a variable input: ``P_{3}(4)`` gives `` 2.3333``. But I still find it a problem that ``P_{3}`` gives `` function_handle with value: @(u_)((n+1)*P_{n+1}(u_)-n*P_{n}(u_))/(2*n+1)``, because n=4. This make the code difficult to check analytically. – Matt Majic Jun 24 '21 at 13:04
  • Indeed, it’s hard to check and it’s also highly inefficient. Do use the representation I recommend, it fixes both issues. – Cris Luengo Jun 24 '21 at 13:13
  • @CrisLuengo, I intend to integrate over the Legendre polynomials numerically. Is that possible with the representation you suggest? – Matt Majic Jun 24 '21 at 13:23
  • 2
    Yes, much more efficiently. Evaluating that polynomial representation is just a dot product, compared to calling an anonymous function that calls two anonymous functions, which call four more anonymous functions... – Cris Luengo Jun 24 '21 at 13:40
  • K I see how the method I was using is inefficient. But function handles can be used in functions like `integral` and `quadgk` which apply some fancy quadrature. Is this possible with the vector polynomials? – Matt Majic Jun 24 '21 at 13:45
  • Please tag me in your comments with `@Cris` to notify me of your comment. Otherwise I only see it by chance... You can create an anonymous function that calls `polyval`. The approach would allow computing the polynomial factors once, when you construct it, rather than every time you evaluate the polynomial. – Cris Luengo Jun 24 '21 at 15:32
  • And it's not just about the size of the variables: the type of `y` could have been anything. And Matlab does not have a generalized method of formatting arbitrary values as literal expressions. (`mat2str` only works on basic primitive types.) Plus what if `y` occurred several times in the function's code? Easier to understand if it's a variable. Finally, if `y` is a `handle` object, its value is actually mutable, and could change between subsequent calls on your anonymous function. – Andrew Janke Sep 18 '21 at 17:11

1 Answers1

7

When you create the function handle g = @(x) f(x).*y, the current values of the variables f and y get "frozen" into g's definition, as discussed in the documentation.

To inspect the actual values of f and y that g uses, you can call functions as follows:

>> info = functions(g); disp(info)
            function: '@(x)f(x).*y'
                type: 'anonymous'
                file: ''
           workspace: {[1×1 struct]}
    within_file_path: '__base_function'

Specifically, see the workspace field:

>> disp(info.workspace{1})
    f: @(x)x.^2
    y: 2
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • 2
    Nice. And as Andras commented in chat: "It makes sense that a closed variable that's a 5000-sized matrix will not be substituted". Copying the variable into the function handle allows for lazy copying. – Cris Luengo Jun 24 '21 at 15:28