Make all local variables available on the matlab command line

Alec Jacobson

October 31, 2019

weblog/

MATLAB is great for prototyping. Certain things are done so well. Anonymous functions are not one of them. Anonymous functions (e.g., myquicktestfun = @(X,Y) X+Y; can be declared in a script (or from command line) workspace (nice for rapid prototyping), but they must be one-liners. This is so dumb, and probably only explainable as a result of some legacy syntax design/parsing mistake. Often you can do some gymnastics to condense a bunch of lines into one. If you can't then you need to literally make a file with the name of your function (e.g., myquicktestfun.m) or you have to move your and populate it with your lines. This is anti-thical to rapid prototyping. And not just for the obvious reason that it's cumbersome and tedious to open a bunch of temporary files. The issue I ran into today is that it make it difficult to debug.

Consider I'm prototyping the following test_script.m:

A = 1;
B = 2;
myfun = @(X,Y) X+Y;
C = myfun(A,B);

Now, suppose I'd like to replace X+Y with two lines [~,Z] = someotherfun(Y); X+Z. Since Z comes as the second output argument I can't easily smoosh this into a one-liner (this is an example; there are many other reasons why you might need/want multiple lines in a function... duh!). So I'm either forced to make a new file myfun.m or to convert my test_script.m into test_fun.m and then I can declare myfun as a multi-line function:

function test_fun
  A = 1;
  B = 2;
  function res = myfun(X,Y)
    [~,Z] = someotherfun(Y);
    res = X+Z;
  end
  C = myfun(A,B);
end

Converting the script to a function might be the way to go if I have lots of anonymous functions that may need to be turned into real, multi-line functions and I don't want to manage a bunch of .m files.

However, I've ruined the rapid prototyping nature of my script. When I was using test_script, after execution or upon an error I'm reset to the command line workspace. This has an important difference with the (awkward) debugger state that I'd need to use if I want access to all the variables introduced in the code above. For example, if I add a breakpoint or the line keyboard in the function above:

function test_fun
  A = 1;
  B = 2;
  function res = myfun(X,Y)
    [~,Z] = someotherfun(Y);
    res = X+Z;
  end
  C = myfun(A,B);
  keyboard
end

I'll have read access to variables A, B, and C so I can print out their values or pass them to functions (e.g., visualization etc.). But I cannot introduce a new variable,

K>> err = A+B - C;
Attempt to add "err" to a static workspace.
 See Variables in Nested and Anonymous Functions.`

Booo. This is just as frustrating as one-linear anonymous functions. I can access variables, call functions (which assign their own internal variables), but can't assign a variable. I'd be happy even with a temporary "debug workspace" (maybe this exists?).

To remedy this, I developed an absurd, very MATLABberish, workaround. If I add the following line to my script (or execute it within the debugger), then all local variables will be added to the command line's workspace:

cellfun(@(v) assignin('base',v,evalin('caller',v)),who);

So then from the command line I can issue:

>>> test_fun(); A A = 1 B A = 2

Note: I must include the obligatory concession that most languages handle anonymous functions correctly in this regard (Python, Ruby, C++11, etc.). AFAIK, MATLAB is the only language that screwed this up.