Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Scalar assignment and nargout bump

Asked by Jim Hokanson on 14 Aug 2013

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

Matt J on 14 Aug 2013

Seems like you're re-inventing the DEAL command, aren't you?

Jim Hokanson on 14 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 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.

Jim Hokanson

Products

No products are associated with this question.

1 Answer

Answer by Matt J on 14 Aug 2013
Edited by Matt J on 14 Aug 2013
Accepted answer

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 on 14 Aug 2013

Yeah, that took me way too long to realize I just needed to do the assignment internally in the function.

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 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.

Matt J

Contact us