Equivalent of inputname() for output variables

Say I have a function:
function B = myfun(A)
disp(inputname(1))
disp(outputname(1))
B = A;
If I call it from the command line as follows:
C = 1;
D = myfun(C)
I get:
C
Undefined function 'outputname' for input arguments of type 'double'.
Error in myfun (line 3)
disp(outputname(1))
That's because, unlike inputname(), which returns the name of the input variables in the caller workspace, an equivalent function for output variable names, outputname(), does not exist. My question is, is there any way of getting the names of output variables in the caller workspace?

6 comentarios

Georges
Georges el 14 de Abr. de 2015
You're not alone. I was just searching for the solution to the same problem.
Geoff Hayes
Geoff Hayes el 15 de Abr. de 2015
Georges - why do you want the names of the output variables?
Matt J
Matt J el 30 de Nov. de 2022
Editada: Matt J el 30 de Nov. de 2022
One use case: I would like to write a function that allows the user to develop the outputs interactively at the K>> prompt:
[A,B,C]=interactive('A','B','C')
function varargout=interactive(varargin)
strList="{"+strjoin(varargin,', ')+'}';
disp("Create the following variables at the K>> prompt : "+strList)
disp("Then issue DBCONT when done.");
keyboard
varargout=eval(strList);
end
However, the above implementation is a little clunky because I have to pass in the list of expected output variable names {'A','B','C'} as input to interactive(). With an outputname() function, this would be unnecessary. I could generate the list automatically.
Such an approach would fail if your function was called with something other than a raw variable name as an output argument. In that same situation for input arguments inputname returns ''. In each of those interactive() calls below, what would you hope to receive from the hypothetical outputname function for each of the output arguments?
c = cell(1, 3);
[c{:}] = interactive()
c = 1×3 cell array
{[1]} {[4]} {[27]}
[a(1), b(2), d(4)] = interactive()
a = 1
b = 1×2
0 4
d = 1×4
0 0 0 27
[~, n] = interactive()
n = 4
e = cell(1, 2);
f = cell(1, 0);
g = cell(1, 1);
[e{:}, f{:}, g{:}] = interactive()
e = 1×2 cell array
{[1]} {[4]}
f = 1×0 empty cell array
g = 1×1 cell array
{[27]}
% Dummy interactive() function so the code above runs.
function varargout = interactive()
varargout = {1, 4, 27};
end
Matt J
Matt J el 30 de Nov. de 2022
what would you hope to receive from the hypothetical outputname function for each of the output arguments?
Similar to inputname, I would want outputname to return empty for such arguments. I would then parse the list and process only outputs with valid outputnames.

Iniciar sesión para comentar.

 Respuesta aceptada

Jan
Jan el 16 de Abr. de 2015
Editada: Jan el 16 de Abr. de 2015
You can do this by obtaining the caller tree by dbstack and parse the corresponding line of the calling M-file.
But I strongly recommend not to do this. The processing should not be based on the names of variables, because varaibales belong to the program, while the program should operate on the data. So mixing the program's source code with the operations on the data is a anti-pattern for clean programming. Such meta-programming increases the complexity of code dramatically. It is the opposite of the information-hiding principle in the object oriented programming. So even inputname is a strange command from this point of view.
Remember that such methods must fail, when the code is compiled.
When the names of the variables really matter, it would be a clean way to program this explicitly:
Data.A = 1:5;
Data.ReturnVariable = 'B';
Data = myfun(Data);
function Data = myfun(Data);
Data.(Data.ReturnVariable) = Data.A;
This is a little bit longer, but it is clean and clear. You cannot get obstacles like anonymous variables, as calls like this would cause with outputname:
B{3} = myfun(A);
or:
field = 'asd';
S.(field) = myfun(A);

4 comentarios

I can't exactly remember, but I think the reason I wanted this was to write a function to create symbolic matrices, like this:
>> J = sym_mat(2, 2)
J =
[J_11 J_12,
J_21 J_22]
Pooya89
Pooya89 el 30 de Abr. de 2019
@Jan:
I just wanted to mention that such functionality (inputname and the missing outputname) could be also very useful for anything related to the user interface (such as graph names, warnings, errors, etc).
The same concept as stringification (or other preprocessor directives such as __func__) in C. Matlab is missing a lot of low level flexibility, but I don't think that they should not be added.
John D'Errico
John D'Errico el 1 de Mayo de 2019
Editada: John D'Errico el 1 de Mayo de 2019
Pooya89: If all you want is a function that can create a symbolic matrix with a given name, you could far more easily just pass in the desired name as an input argument. In fact, sym already does something at least close to that.
sym('J',[2 2])
ans =
[ J1_1, J1_2]
[ J2_1, J2_2]
Note that your numvering scheme would fail for symbolic arrays of size 11x11 or larger, as which element does J_111 indicate?
If you really needed to put this into the array of name J, syms already does that automatically.
clear
syms('J',[2 2])
whos
Name Size Bytes Class Attributes
J 2x2 8 sym
J1_1 1x1 8 sym
J1_2 1x1 8 sym
J2_1 1x1 8 sym
J2_2 1x1 8 sym
And it uses a better numbering scheme for the elements. So, while you could have written sym_mat to do exactly the same, why bother to recreate that wheel?
Matt J
Matt J el 30 de Nov. de 2022
Editada: Matt J el 1 de Dic. de 2022
You can do this by obtaining the caller tree by dbstack and parse the corresponding line of the calling M-file.
Unfortunately, that won't work if there is no calling mfile, i.e., if the function is invoked from the command line (though potentially you could parse History.xml).
It also won't work when the call is made using a function handle.
fhandle=@Func;
[A,B]=fhandle(); C=sin(pi) %(*)
function varargout=Func
varargout={1,2};
s=dbstack('-completenames');
currentFunction=s(1).name
end
In the example above, the command s=dbstack('-completenames') produces information that Func() is executing, but no information about which of the commands in line (*) has invoked it,
currentFunction =
'Func'

Iniciar sesión para comentar.

Más respuestas (1)

Matt J
Matt J el 1 de Dic. de 2022

0 votos

I've implemented Jan's idea in this FEX submission,
but it has some caveats (see below)
>> [A, ~, C]=func()
A =
'a'
C =
'c'
function varargout=func()
varargout=lower(outputnames);
end
The caveats are,
1. The line of code or the command line where the function call is
made must contain no other commands. The above example would fail,
had we done,
[A,B]=func(); [C,D]=func()
2. Function calls where the outputs contain indexing expressions
will have unjpredicatable behavior, e.g.,
[A{1,2}]=func()

Preguntada:

el 21 de Jul. de 2014

Respondida:

el 1 de Dic. de 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by