variable number of outputs

I want to build a matlab function with outputs whose number/length is variable. Below is my code, which somehow returns an error:
function varargout=polyargout(x)
if x==1
nargout=1;
varargout{1}=1;
elseif x==2
nargout=2;
for i=1:x
varargout{i}=magic(i);
end
end
Basically one doesn't know how many outputs to return until running the function. To call the function, I wish to use:
y=polyargout(1) to get y=1
y=polyargout(2) to get y=[magic(1),magic(2)]

 Accepted Answer

Stephen23
Stephen23 on 4 Dec 2018
Edited: Stephen23 on 4 Dec 2018
It appears that you want to do something like this:
function out = polyargout(x)
if x>1
out = arrayfun(@magic, 1:x, 'uniform', 0);
else
out = 1;
end
end
And tested:
>> polyargout(1)
ans = 1
>> C = polyargout(3);
>> C{:}
ans =
1
ans =
4 3
1 2
ans =
8 1 6
3 5 7
4 9 2
As noted in my earlier comments, although you asked about "variable number of outputs", what you showed and requested is just one output (either a numeric array or a cell array of numeric arrays, depending on the value of x): "To call the function, I wish to use:"
y=polyargout(1) to get y=1
y=polyargout(2) to get y=[magic(1),magic(2)]

1 Comment

It turns out vargout has a special meaning, where nargout needs to come in. I shouldn't have used it here.

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 2 Dec 2018
Edited: Walter Roberson on 2 Dec 2018
Nothing inside the function can force a different number of outputs of the function. However, things inside the function can affect the content of what is output.
function v = polyargout(x)
v = cell(1, x);
for i = 1 : x
v{i} = magic(i);
end
end
Or more compactly for this case,
function v = polyargout(x)
v = arrayfun(@magic, 1:x, 'uniform', 0);
end
For both of the above, examples would include
y = polyargout(1); %returns a cell with a single entry
y = polyargout(3); %returns a 1 x 3 cell
It is possible to recognize the number of output arguments supplied:
function varargout = polyargout
for i = 1 : nargout
varargout{i} = magic(i);
end
end
For this, examples would include
y = polyargout; %returns a single variable that contains a numeric array
[y1, y2, y3] = polyargout; %returns three variables, the first magic(1), the second magic(2), the third magic(3)

8 Comments

When I use either
function v = polyargout(x)
v = cell(1, x);
for i = 1 : x
v{i} = magic(i);
end
end
or
function v = polyargout(x)
v = arrayfun(@magic, 1:x, 'uniform', 0);
end
they didn't give me the following results:
y = polyargout(1); %returns a cell with a single entry
y = polyargout(3); %returns a 1 x 3 cell
Instead, both y = polyargout(1) and y = polyargout(3) return '1'.
Stephen23
Stephen23 on 3 Dec 2018
Edited: Stephen23 on 3 Dec 2018
They work exactly as expected for me:
>> fun = @(x) arrayfun(@magic, 1:x, 'uniform', 0);
>> C = fun(3);
>> size(C)
ans =
1 3
>> C{:}
ans =
1
ans =
4 3
1 2
ans =
8 1 6
3 5 7
4 9 2
What do you expect those functions to do?
The two functions you've written will return a 1x3 cell array given an input of 3. If that's not what you get, either you're using different code, or you're calling a different polyargout function than the one you think you're calling.
which polyargout -all
to check that there isn't another polyargout.m shadowing the function you're editing.
An important note: your question asks about a variable number of outputs, but actually all your examples show a function with just one output, y. What is varying is the number of elements in that single output.
a a
a a on 4 Dec 2018
Edited: a a on 4 Dec 2018
Thank you so much. Your inline function arrayfun works (gives a 'cell' result). But putting the exact thing into a function (not inline) always gives me a 'double' result. That's strange.
My purpose is to use an ambigous command line y=polyargout(x) to return a double or cell depending on x. I don't want to explicitly write y or [y,z] etc because one doesn't know how many components there'll be before running the program. For instance, y could be a scalar while z a matrix.
However, I still prefer writing a function unlike arrayfun, because my real purpose isn't about running sth like 1:x but just running x. I need x to be a scalar.
Stephen23
Stephen23 on 4 Dec 2018
Edited: Stephen23 on 4 Dec 2018
"But putting the exact thing into a function (not inline) always gives me a 'double' result."
I tried your polyargout function and it works exactly as expected:
>> C = polyargout(3);
>> C{:}
ans =
1
ans =
4 3
1 2
ans =
8 1 6
3 5 7
4 9 2
You should use which to check which function is being called: perhaps you have other functions with the same name? Or perhaps you actually defined your function using varargout and not v as you showed in your comment?
You seem to be getting a bit confused about the difference between multiple outputs (which is what you ask about in your question "variable number of outputs") and the code in your comments which only have one output argument (which you called v). One output argument v is not the same thing as multiple output arguments (e.g. using varargout). So which do you really want?
"My purpose is to use an ambigous command line y=polyargout(x) to return a double or cell depending on x."
Sure, MATLAB does not require input/ouput classes to be fixed, so you can easily write code to return different ouput depending on the input arguments.
"I don't want to explicitly write y or [y,z] etc because one doesn't know how many components there'll be before running the program. For instance, y could be a scalar while z a matrix."
It sounds like you want just one output argument, which could be a cell array with as many cells as you want (just like your example functions do, from your earlier comment). As an alternative you could use a comma-separated list, but I would not recommend this.
"My purpose is to use an ambigous command line y=polyargout(x) to return a double or cell depending on x."
From a design point of view, this is not a very good idea. Any caller would then have to check what type of output it has received. I would recommend a consistent output type (as your example function actually does), so always a cell array. Your double could be returned as a scalar cell array containing that double.
OK, let me rewrite the code:
function varargout=polyargout(x)
if x==1
varargout={1};
else
varargout{1}=2;varargout{2}=eye(2);
end
But y=polyargout(x) still outputs 'double' for any x's, unless using [a,b]=polyargout(x).
My real purpose: originally I wrote [a,b]=f(x). For instance, 'a' could be a scalar while 'b' a matrix. But for certain x's, 'b' won't be defined in f(x), so there'll be only 'a' valid to be output. That's why I won't know how many variables to output beforehand. If there's a way to make this polyargout possible, I don't need to check what kind of output type I get, because according to my function definition, I'll know when the output will be a single variable and when it'll be a cell.
I don't have any other functions with the same name in the same directory.
Stephen23
Stephen23 on 4 Dec 2018
Edited: Stephen23 on 4 Dec 2018
"But y=polyargout(x) still outputs 'double' for any x's, unless using [a,b]=polyargout(x)."
Not at all the same thing. varargout defines multiple output arguments with the contents of its cells, which is exactly what you describe. For example, if you specify varargout to have three cells, then when you call the function it can be called with up to three outputs:
[A,B,C] = polyargout(x)
where the variables A, B, and C are allocated the contents of varargout. Using varargout is special syntax, unrelated to your earlier comments where you defined one cell array named v and returned that one single output argument.
"That's why I won't know how many variables to output beforehand"
Then returning one cell array is probably the simplest and most intuitive solution.

Sign in to comment.

Asked:

a a
on 2 Dec 2018

Commented:

a a
on 7 Dec 2018

Community Treasure Hunt

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

Start Hunting!