Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I can reproduce: anonymous functions for me are capturing copies of <em>all</em> variables in the enclosing workspace, not just those referenced in the expression of the anonymous function. </p> <p>Here's a minimal repro.</p> <pre><code>function fcn = so_many_variables() a = 1; b = 2; c = 3; fcn = @(x) a+x; a = 42; </code></pre> <p>And indeed, it captures a copy of the whole enclosing workspace.</p> <pre><code>&gt;&gt; f = so_many_variables; &gt;&gt; f_info = functions(f); &gt;&gt; f_info.workspace{1} ans = a: 1 &gt;&gt; f_info.workspace{2} ans = fcn: @(x)a+x a: 1 b: 2 c: 3 </code></pre> <p>This was a surprise to me at first. But it makes sense when you think about it: because of the presence of <code>feval</code> and <code>eval</code>, Matlab can't actually know at construction time what variables the anonymous function is actually going to end up referencing. So it has to capture everything in scope just in case they get referenced dynamically, like in this contrived example. This uses the value of <code>foo</code> but Matlab won't know that until you invoke the returned function handle.</p> <pre><code>function fcn = so_many_variables() a = 1; b = 2; foo = 42; fcn = @(x) x + eval(['f' 'oo']); </code></pre> <p>The workaround you're doing - isolating the function construction in a separate function with a minimal workspace - sounds like the right fix.</p> <p>Here's a generalized way to get that restricted workspace to build your anonymous function in.</p> <pre><code>function eval_with_vars_out = eval_with_vars(eval_with_vars_expr, varargin) % Assign variables to the local workspace so they can be captured ewvo__reserved_names = {'varargin','eval_with_vars_out','eval_with_vars_expr','ewvo__reserved_names','ewvo_i'}; for ewvo_i = 2:nargin if ismember(inputname(ewvo_i), ewvo__reserved_names) error('variable name collision: %s', inputname(ewvo_i)); end eval([ inputname(ewvo_i) ' = varargin{ewvo_i-1};']); end clear ewvo_i ewvo__reserved_names varargin; % And eval the expression in that context eval_with_vars_out = eval(eval_with_vars_expr); </code></pre> <p>The long variable names here hurt readability, but reduce the likelihood of collision with the caller's variables.</p> <p>You just call eval_with_vars() instead of eval(), and pass in all the input variables as additional arguments. Then you don't have to type up a static function definition for each of your anonymous function builders. This'll work as long as you know up front what variables are actually going to be referenced, which is the same limitation as the approach with <code>getJacobianHandle</code>.</p> <pre><code>Jv = eval_with_vars_out(['@(v,f,rho) ' Jv_str],listConnected,areaPipes,endNodes,D,L,g,dz); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload