Scalar assignment and nargout bump

1 view (last 30 days)
I am trying to do the following:
s = [objs.s] % s may be a struct array (really object array) or empty []
[s.prop] = assignToStructureArray(scalar_value);
where
function varargout = assignToStructureArray(value)
varargout(1:nargout) = {value};
end
This works fine unless s is empty, in which case nargout is 1, not 0 and suddenly s is no longer empty.
This brought me to Loren's Blog post which greatly confuses me. http://blogs.mathworks.com/loren/2009/04/14/convenient-nargout-behavior/
I'm really having trouble understanding why the nargout bump is a good idea. It seems to me like this is just another Matlab corner case that while sometimes convenient is not a good idea.
Any help on understanding the post and more importantly, on how to change the code to work without having to resort to an if statement before making the function call that checks whether s is empty or not would be great.
Thanks, Jim
  3 Comments
Jim Hokanson
Jim Hokanson on 14 Aug 2013
Edited: Jim Hokanson on 15 Aug 2013
Deal actually works slightly differently. You'll notice I'm only passing in a single value and having it replicated to all outputs, not dealing a set of inputs to a set of outputs.
CORRECTION: I was not aware of the scalar behavior. See comment by Matt J below. The end result is that deal would normally be exactly what is needed, unless via filtering it is possible that the structure being assigned to is empty [], then deal will not function correctly.
My goal is to write a function which removes the initial setup of performing deal. Those steps are replication and then transfering data to a cell format so that they can be passed in as multiple inputs to deal.
Something like:
n = 0; %More generally, this would be based on something else
a = num2cell(value*ones(1,n));
deal(a{:})
Second, the problem still exists with the deal command. In this case the deal command has a check that knows the number of inputs doesn't match the number of outputs, so it throws an error instead of suddenly making your empty output have a size of 1, via the "nargout bump"
So most generally the goal is to assign a scalar to a field in a structure array in one line (function calls are fine).
i.e. something like this (where this example obviously doesn't always work, or more accurately, only works when s is a scalar):
[s.prop] = value;
My guess is that the one line assignment like this is impossible to do because of the "nargout bump" but I'd be happy to be wrong. Also, besides a solution I'd welcome any comments that explain to me the "nargout bump" and why it isn't a bad idea.
Final thoughts:
As I'm writing this I realized I can always do:
s = myFunction(s,field,value);
I'll probably go with this for now but if anyone can provide an alternative solution or insight on the "nargout bump" I'd appreciate it.
Matt J
Matt J on 14 Aug 2013
Edited: Matt J on 14 Aug 2013
My goal is to write a function which removes the initial setup of performing deal. Those steps are replication and then transfering data to a cell format so that they can be passed in as multiple inputs to deal.
I'm not sure when this comment occurred in the flow of our conversation, but hopefully you're now aware that it is not necessary to replicate scalars with deal(). The single line of code
[s(1:n).prop]=deal(scalar)
will distribute the scalar n times exactly as you would hope.

Sign in to comment.

Accepted Answer

Matt J
Matt J on 14 Aug 2013
Edited: Matt J on 14 Aug 2013
To me, a better justification (if there is one) for the nargout bump is to make it easier to write wrappers for the many builtin functions tht always return at least 1 argument, even when called with nargout=0. For example, at the command line, SORT always returns at least one output arg, even when one is not explicitly requested,
>> sort([5 1 3]) % call with no arguments
ans =
1 3 5
Suppose I now want to write a wrapper for sort() such that its 2nd argument returns 0-based indices instead of 1-based indices. Then I can do so, while preserving the above behavior, as easily as
function varargout=mysort(varargin)
[varargout{1:nargout}]=sort(varargin{:});
if nargout>1, varargout{2}=varargout{2}-1;
end
whereas without the bump, I would have to do something more complicated,
function varargout=mysort(varargin)
[varargout{1:max(1,nargout)}]=sort(varargin{:});
if nargout>1, varargout{2}=varargout{2}-1;
end
to ensure that at least one output arg was always returned. To my tastes, I would rather endure the second syntax for consistency's sake, but maybe that's just me...
  4 Comments
Jim Hokanson
Jim Hokanson on 14 Aug 2013
Ok, I think I'm starting to get it.
Without the bump,
[varargout{1:nargout}] = sort(values)
would throw an error, since we have one output from sort, but no outputs requested from the mysort caller, meaning varargout{1:0} would be empty and not a valid assignment for the output from sort.
Another alternative, that get's back to Oliver's example (#1 in Loren's post), would be:
if nargout
[varargout{1:nargout}] = sort(values);
%Additional code possible here
else
varargout = {}
sort(values);
end
In which I'm keeping the function call in case the function were to make some sort of global call or change some seed (I don't think sort does but it's just an example).
More generically, one could write:
fh = @() myFunction(varargin{:});
if nargout
[varargout{1:nargout}] = fh();
else
varargout = {};
fh();
end
This might be advantageous when the calling form of the function is likely to change so you only need to edit it in one place.
Anyway, I think I get it now. I'm glad you to hear you also disapprove, or at least would prefer the consistency that the second approach offers.
It isn't clear how anonymous functions come into play with this. Any thoughts on that?
Matt J
Matt J on 16 Aug 2013
It isn't clear how anonymous functions come into play with this. Any thoughts on that?
Nope. It was unclear to me, too.

Sign in to comment.

More Answers (0)

Categories

Find more on Argument Definitions in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!