Can a function known whether/which specific output is ignored (tilde operator)?

30 views (last 30 days)
A function can know the number of requested outputs via nargout.
But can it know if a specific output is replaced with tilde operator (~) ?
[x,~,z] = foo();
function [a,b,c] = foo()
% how to know that the second output is not needed?
end
  26 Comments
royk
royk on 21 Aug 2020
thanks so much everyone for the thorough and careful assessment
I actually finds Adam's detectOutputSuppres​sion() quite helpful even if it doesn’t resolve all cases. the function should really just let you know whether or not it was able to determine the outputs (namely when there was no use of dot or {} in the output line; and only one call to the function on the caller line).
Another more general approach is perhaps for detectOutputSuppres​sion() to evaluate in the caller any curly brace or dot indexing of the output variables to see how many outputs they produce.
Adam Danz
Adam Danz on 21 Aug 2020
Thanks royk. I've carefully considered the feedback and will update the function soon.

Sign in to comment.

Accepted Answer

Adam Danz
Adam Danz on 15 Sep 2020
Edited: Adam Danz on 16 Sep 2020
"Can a function known whether/which specific output is ignored ?"
No. nargout tells you the number of output arguments specified in the caller but it counts outputs suppressed with a tilde (~). nargout(fun) tells you the number of ouputs a specific function has to offer but that tells you nothing about the caller.
What are the alternatives?
1. Pass an input to the function that specifies which outputs you're requesting. The tricky part is to remember to change that input value if a different set of outputs is requested.
2. Prioritize your outputs and use nargout to determine which outputs to produce.
You can also try the new and improved (vs.2.0.0) detectOutputSuppression() from the file exchange. It reads the caller line and parses the outputs to determine if any are suppressed.
Example
The main() function calls myFunc() and suppresses the 2nd and 3rd outputs.
function main()
[mst(1), ~, ~, data] = myFunc();
function [a, b, c, d] = myFunc()
a = 1; b = 2; c = 3; d = 4;
isTilde = detectOutputSuppression(nargout);
Result: isTilde = [0 1 1 0].
Supported syntaxes
  • [a,~,~,d] = myFunc();
  • a = myFunc();
  • [a(1),a(2),~] = myFunc();
  • [~,~,c(1:20),~] = myFunc();
  • [~,b{3}] = myFunc();
  • [~,b{3,1,5}] = myFunc();
  • [~,~,~,g{1}{2}{4}(1)] = myFunc();
  • q=cell(1); [~,q{:}] = myFunc(); % because q is 1x1.
  • T=table(); [T.a,~] = myFunc();
  • [j,u,n,k]; [~,~,~,~] = myFunc(); [j,u,n,k]
  • [j,u,n,k], [~,~,~,~] = myFunc(), [j,u,n,k]
  • S=struct; [S.x,~,S.t(4)] = myFunc();
  • [v.a, v.b{1}, v.c(2,2), ~] = myFunc();
  • myFunc + 1;
  • y = [1, myFunc(), 1];
  • assert(~isempty(myFunc()))
  • [a,b,~,~] = myFunc(...
  • inputs); %split in multiple lines after function name
  • and more....
Syntaxes not supported
An error message is thrown when these syntaxes are detected.
  • Outputs not separated by commas: [a b c] = myFunc()
  • When myFunc() is not called from within an m-file or wasn't the most recent command called from the command window.
  • When myFunc() is called in debug mode but isn't the line currently paused or executed by MATLAB.
  • Output assignment to comma separated lists: x=cell(1,5); [x{:}] = myFunc();
  • Caller line is split into multiple lines before the inputs (a split after the function name is OK).
  • When myFunc() is wrapped in an anonymous function: f = @myFunc; f()
  • When the parser matches more than one [...]=myFunc per line of code.
  2 Comments
Stephen23
Stephen23 on 1 Dec 2022
"Supported syntaxes"
are not robust if they contain any comma-separated list (not just ones from a cell array, as Adam Danz wrote), In fact this also includes structures and strings:
This means that some syntaxes in the list are not possible to robustly detect, for example:
[v.a, v.b{1}, v.c(2,2), ~] = myFunc();
Some other syntaxes are also not robust because of MATLAB's weak typing:
table = @() struct('a',{1,2,3}); % could be any size.
...
T = table() % oops, not an instance of the table class.
T = 1×3 struct array with fields:
a
[T.a,~] = myFunc() % how many outputs?
On top of that we have the possibility of EVAL/ASSIGNIN/etc replacing or clearing any variable... which all just proves, that the number/ignored output arguments can only be determined at runtime.

Sign in to comment.

More Answers (2)

Bjorn Gustavsson
Bjorn Gustavsson on 19 Aug 2020
Edited: Bjorn Gustavsson on 19 Aug 2020
I'll merge parts of two of my comments to provide a KISS-type suggestion:
In a "gentle-downhill-slope-home" use-case you might be able to sort your a, b and c such that the expensive and avoidable output is the third output - then you can check how many outargs there are with nargout. That way you can avoid the expensive calculation if you only have 2 outputs, this generalizes well in some cases.
If this is a big problem in terms of time-consumption, then re-write the function with an optional argument, call it something like whichargouts that directs the function excecution. You could make it a bolean array with 1 for requested outputs. If the user doesn't supply the time-saving directive, no time-saving is made (too bad), if directives are given then time-savings are made. This is a QD-solution to a programming-wise tricky problem, but should work until a neat and robust automatic solution is available.
HTH

Matt J
Matt J on 1 Dec 2022
You can do it with this FEX download,
but there are some caveats to its use, mentioned in the documentation.
[x,~,z,~] = foo()
function [a,b,c,d] = foo()
[a,b,c,d]=deal([]);
unused=find(outputnames=="~")';
if ~isempty(unused)
disp("These outputs are not used:"+mat2str(unused));
end
end
These outputs are not used:[2;4]
x =
[]
z =
[]

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!