0
votes

I'm trying to use Matlab's inputParser for the first time, and I have to say I'm finding it a bit confusing. I am unable to successfully provide an anonymous function as an optional parameter.

This is the function I am passing arguments to

function myfun(str,bounds,varargin)
p = inputParser;
p.FunctionName = mfilename;
p.addRequired('str',@isstr);
p.addRequired('bounds',@isvector);
p.addOptional('str_latex','',@isstr);
p.addOptional('seed',[], @(x) isa(x,'function_handle'))
p.parse(str,bounds,varargin{:});
p.Results
% do something here
end

And I am calling it like this...

myfun('str', 'epsilon',...
'str_latex', '\epsilon',...
'bounds', [0 1],...
'seed', @() betarnd(2,2))

But I get an error:

Error using my fun The value of 'seed' is invalid. It must satisfy the function: @(x)isa(x,'function_handle').

I suspect a simple error, but I cannot figure it out.

1
One unrelated issue is that you're passing the wrong inputs to p.parse. Since you're passing str and bounds with their property names, str and bounds being passed to p.parse are actually 'str' and 'bounds' - excaza
I'm not sure when you selected the answer, but I added more explanation to the answer and more paths forward. - TroyHaskin

1 Answers

3
votes

Name-value pairs are declared using the addParameter method (R2013b+, addParamValue prior to that). addRequired and addOptional do not have name-value pairs associated with them, simply identifying/documenting argname inputs for internal use and association with the parsed struct. It appears you want to use all addParamter-s in this use case.


The main idea behind the three input types is

  • Required: the very first arguments with explicit, documented inputnames that absolutely need to be supplied by the user for the function to perform properly.
  • Optional: arguments that typically follow Required arguments with explicit, documented inputnames that are often input by the user for customized behavior.
  • Name-Value: arguments that typically follow Optional arguments with a name specifying the value to be set are often input by the user for customized behavior but not so often as to be given an upfront, explicit parameter like Optional arguments.

In my experience, Required arguments are almost always obvious, for good, well-defined functions, while Optional and Name-Value is more experience-, complexity-, and aesthetics-based. A simple example would be linspace: the start and end of the interval are absolutely needed for the function to work, but not necessarily the number of points which can be left to 100 by default, but giving it an explicit name-value pair is a little overkill. A more complex example would be the plot function: at a minimum y data is needed, then x,y pairs of data, then x,y,linSpec sets of data, and then a whole list of specific name-value pairs for pinpoint customization that users can use if they so choose.

With your input parser as written, the call sequence should be:

myfun('epsilon',[0,1],'\epsilon',@() betarnd(2,2));

Since no name-value pairs were declared, none exist, but the Optional arguments still have a positional order associated with them. You can re-write your parser as:

function myfun(varargin)
    p = inputParser;
    p.FunctionName = mfilename;
    p.addParameter('str',[],@isstr);
    p.addParameter('bounds',[],@isvector);
    p.addParameter('str_latex','',@isstr);
    p.addParameter('seed',[], @(x) isa(x,'function_handle'))
    p.parse(str, bounds, varargin{:});
    p.Results
    % do something here
end

For something like the generic input sequence you may have been expecting. Notice that I used []-s to fail the simple validations without a good error message; you should add a good error message indicating that those name-value pairs are required for proper functionality, or do as you were doing and have explicit, upfront Required inputs with addRequired but without the name-value semantics.