32

mini-example:

function varargout = wrapper(varargin)
varargout = someFunction(varargin);

That's how I'd do it first. But for example if someFunction = ndgrid this yields a not defined for cell arrays error, so the next try was using someFunction(varargin{:}) instead. That's a successful call, but calling [a,b] = wrapper([1,2], [3,4]) does not yield the same result as a direct call to ndgrid, so what am I doing wrong?

Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221

3 Answers3

38

Actually, Mikhail's answer is not quite right. In the case that someFunction is a function that returns a value even if none is requested, which is how a function indicates that the value should be assigned to ans, Mikhail's wrapper will fail. For example, if someFunction were replaced with sin and you compared running wrapper versus running sin directly, you'd see:

>> wrapper(0)
>> sin(0)

ans =

   0

The right way to do this is

function varargout = wrapper( varargin )
[varargout{1:nargout}] = someFunction( varargin{:} ); 

The reason this works is due to a little known edge case in MATLAB indexing rules that has existed precisely for this case since at least R2006a (probably longer). It is something of a wart in MATLAB indexing but was deemed necessary to handle this sort of thing.

The rule is:

When performing subscripted assignment, if

  • subscripted-assigning to an uninitialized variable, AND
  • the uninitialized variable is curly-brace indexed, AND
  • the index in the curly braces is empty, AND
  • the left-hand side appears inside square braces, AND
  • the right-hand side resolves to a value / returns an output

Then the uninitialized variable is assigned a scalar cell containing the value returned by the right-hand side.

For example:

>> clear uninit % just to make sure uninit is uninitialized
>> [uninit{[]}] = sin(0)

uninit = 

    [0]
SCFrench
  • 8,244
  • 2
  • 31
  • 61
  • 2
    +1 and thanks this deep insights! Where did you get the rules above? – Mikhail Poda Feb 06 '11 at 09:03
  • 8
    Well, to be honest, it helps if you have access to the source code... I work for The MathWorks. I'm not sure if this is documented anywhere officially. It's one of those things that helps the advanced user but could easily completely confuse beginners. However, I'm confident this behavior will not change, because its needed to handle this case. – SCFrench Feb 06 '11 at 14:56
  • Thanks for sharing, this had bugged me for a long time! – Erik Aug 03 '16 at 09:05
  • Good knowedge, thank you! I think I may have been using this without even realizing why it works :-) – Luis Mendo Feb 19 '21 at 15:47
6
function varargout = wrapper( varargin )

if ~nargout
    someFunction( varargin{:} ); 
else
    [varargout{1:nargout}] = someFunction( varargin{:} ); 
end
Mikhail Poda
  • 5,742
  • 3
  • 39
  • 52
1

If the number of output arguments is the same as the number of input arguments, you can use

function varargout = wrapper(varargin)
[varargout{1:nargin}] = someFunction(varargin{:});

This works fine with ndgrid.

mburg
  • 19
  • 1
  • 2
    Apart from the typo (you surely mean varargout{1:nargout}), note that this approach always returns output - hence Mikhail's extra "~nargout" guard. – Edric Feb 04 '11 at 09:45
  • @Edric: I think using `nargin` was on purpose because of the assumption `nargout=nargin`. In that case the `~nargout` guard isn't necessary – Tobias Kienzler Feb 04 '11 at 10:13
  • 1
    @Edric ... also see [SCFrench's answer](http://stackoverflow.com/questions/4895556/how-to-wrap-a-function-using-varargin-and-varargout/4910926#4910926) why the guard actually does not yield the desired behaviour – Tobias Kienzler Feb 06 '11 at 15:34