addParameter adds a Parameter/Value pair to the input syntax of your function. For example, if you had a function called myFunction in which you were using the input parser:

addRequired(p,'x')
addParameter(p,'Foo',1)

Would add:

myFunction(x,'Foo',value)

As a valid syntax with a default value of 1. In parameter value pairs, the name of the parameter is specified with a string or character array, followed by a value specification.

addOptional(p,'Foo',value)

Would add:

myFunction(x,value)

As an optional positional argument. In this case, you only specify the value of the optional argument without specifying a parameter name.

Answer from Alex Taylor on Stack Overflow
🌐
MathWorks
mathworks.com › matlab › programming › functions › argument definitions
addOptional - Add optional, positional argument into input parser scheme - MATLAB
addOptional(p,argName,defaultVal) adds an optional, positional input argument, argName, into the input parser scheme p.
🌐
MathWorks
mathworks.com › matlab › programming › functions › argument definitions
inputParser - Input parser for functions - MATLAB
You can define your input parser scheme by calling the addRequired, addOptional, and addParameter functions in any order.
🌐
MathWorks
mathworks.com › matlabcentral › answers › 79078-what-is-the-difference-between-addoptional-and-addparamvalue-when-using-the-inputparser-class
What is the difference between addOptional and addParamValue when using the inputParser class? - MATLAB Answers - MATLAB Central
June 14, 2013 - As near as I can tell the difference between addOptional and addParamValue is that addOptional, like addRequired, is a POSITIONAL input, and cannot be added to the function call in arbitrary order as you can with addParamValue. In other words, it's not a name/value pair. Sign in to comment. Sign in to answer this question. ... Find the treasures in MATLAB Central and discover how the community can help you!
🌐
GitHub
github.com › danm0nster › mdembedding › issues › 1
use of undocumented inputParser.addOptional behaviour · Issue #1 · danm0nster/mdembedding
August 30, 2019 - The inputParser.addOptional method is being used for the optional arguments. addOptional is meant for positional arguments, i.e., arguments that are interpreted based on their position of the argument list. From mathworks documentation: ...
Author: danm0nster
Find elsewhere
Top answer
1 of 2
6

I do not recommended the use of inputParser with optional arguments that are allowed to be character arrays, because parse() cannot distinguish if the user passes a parameter name (which is always of type char) or the optional input argument. Thus, it is a logical consequence of this behaviour why you cannot pass a char as an optional input argument.

However, if you specify a validation function for the optional input arguments that may be char, you can make it work. From the addOptional documentation under section ‘Tips’:

For optional string inputs, specify a validation function. Without a validation function, the input parser interprets valid string inputs as invalid parameter names and throws an error.

This is the error your example generated.

Fixing your example

'o' is the optional input argument. If you know how to validate the values 'o' needs to accept, provide a validation function that returns true for those valid inputs. For example, if you know 'o' will always be a char array, try the following (line by line).

a = inputParser; 
addOptional(a, 'o', 'default', @ischar);
addParameter(a, 'p', 1);

parse(a, 'x');  % OK

parse(a, 'Hello, World!', 'p', 2);  % OK

parse(a, 'p', 'p', 'p')  % OK, although quite cryptic

parse(a, 3);  % Throws an error, as expected, because 3 is not a char

parse(a, 'p', 4)  % Throws a somewhat unexpected error, because we meant to set parameter 'p' to value 4

The last line seems counter-intuitive, but it's not! We'd expect the parser to detect the parameter 'p' instead of implicitly assuming it is the character we provide for optional argument 'o', which we wanted to omit. It is the expected behaviour, though, as I will explain now.

Why char optionals give inputParser a hard time

The demonstrated bahviour is expected because both the optional and parameter arguments are not required, i.e., optional. If you'd have two optional input arguments, 'o1' and 'o2', their order matters to the input parser (which is why the MATLAB documentation calls them ‘optional positional arguments’). You could never pass a value for 'o2' before a value for 'o1'. This implies 'o2' can only be used if 'o1' is also specified. In other words, 'o1' impedes the use of any other optional arguments.

The same is true for parameters, which should always come after other optional input arguments (as you already quoted). As such, they behave like optionals if any optional input arguments are allowed to be char. The result is MATLAB's inputParser not knowing if a char input is an optional input argument or a parameter. MATLAB's developers have decided to require explicit ordering of optional inputs, so MATLAB can be sure what optional arguments are passed to parse().

Suggested action if optional inputs may be char

Because using optional input arguments requires MATLAB to assume some input arguments referring to an optional input argument, others referring to parameters, this may result in errors, behaviour or results unexpected by the end-user if not all optional arguments are specified.

Input argument schemes are better if written explicitly to prevent this unexpected implicit behaviour. I suggest that if optional input arguments are required that accept char input, you always make them parameters, i.e., name-value pair arguments using addParameter. Using optional input arguments that accept char input only works if not using any parameters, or by explicitly stating (e.g. in the help) that parameter input argument can be used if and only if all optional input arguments are given as well.

2 of 2
1

The validation function of addOptional is used to determine if the parsed argument corresponds to the parameter specified with addOptional. If the validation function returns false, the current parsed argument is passed to the next addOptional/addParameter

The default validation function of addOptional is a simple ~ischar to distinguish between parameter and value due to performance reasons. See the answer of a TWM employee here. The provided solution however does not cover all use cases.

Below is a solution which works with any datatype, as well as with parameter/value structs. The only caveat: you cannot use a value which is equal to any parameter name.

a = inputParser;

% Validation function needs to check
% - if argument is a parameter name or a value
%   -> any(strcmp(x,a.Parameters))
% - if argument is a parameter/value struct
%   -> isstruct(x) && any(ismember(fieldnames(x),a.Parameters))
addOptional(a,'o','x',@(x)~(any(strcmp(x,a.Parameters)) || isstruct(x) && 
any(ismember(fieldnames(x),a.Parameters))));

addParameter(a, 'p', 1);

%The next three parse commands give all the same result struct

% 'o' as positional parameter
parse(a, 'w', 'p', 2)        

% 'o' as named parameter/value pair
parse(a, 'o', 'w', 'p', 2)   

% parameters provided as param/value struct
pv.o='w';
pv.p=2;
parse(a, pv)

% value of 'o' is a struct
data.x = 1;
parse(a, data)

%You cannot use a value equal to a parameter name
parse(a, 'p', 'p', 2) % FAIL

I suggest you to write a custom function for optional parameters if you don't mind the speed penalty

function addOptionalExt(parserObj,key,default)
parserObj.addOptional(key,default,...
    @(x)~(any(strcmp(x,parserObj.Parameters)) || ...
    isstruct(x) && any(ismember(fieldnames(x),parserObj.Parameters))));

and then use it in your example

a = inputParser;
addOptionalExt(a, 'o', 'x');
addParameter(a, 'p', 1);
parse(a, 'w', 'p', 2)
🌐
MathWorks
mathworks.com › matlabcentral › answers › 1919815-inputparser-addoptional-seems-broken
inputparser addOptional seems broken - MATLAB Answers - MATLAB Central
February 27, 2023 - It seems that if I use addOptional I cannot skip arguments For example, if I wish to have an optional array but I simply pass a color (e.g., 'g') it will always throw 'The Value of 'Yu' is invalid...
🌐
MathWorks
mathworks.com › matlabcentral › answers › 2009-problem-with-addoptional
Problem with addOptional - MATLAB Answers - MATLAB Central
February 25, 2011 - I'm writing a function that has 5 arguments, only one of which is required. So, I'm using a parser and adding the required argument and the optional arguments. It looks something like this: p ...
🌐
MathWorks
mathworks.com › matlabcentral › answers › 2036011-inputparser-addoptional-error
inputParser/addOptional Error - MATLAB Answers - MATLAB Central
October 19, 2023 - I understand that you are getting an error while using the “addOptional” function and are seeking an easire way to perform the task. Please note that in MATLAB, the “addOptional” function in the “inputParser” class is ‘case-insensitive’ for the argument names.
🌐
MathWorks
mathworks.com › matlab › programming › functions › argument definitions
Input Parser Validation Functions - MATLAB & Simulink
The Input Parser methods addRequired, addOptional, and addParameter each accept an optional handle to a validation function.
🌐
University of Massachusetts
people.umass.edu › whopper › posts › better-matlab-functions-with-the-inputparser-class
Will Hopper ~ Better MATLAB functions with the inputParser class
Functions arguments in MATLAB can be rigid and force you to use lots of ad-hoc boilerplate code deal with optional arguments. Using the inputParser class to parse function arguments allows you to give your function named and optional arguments with default values, simply and easily.
Top answer
1 of 2
5

The problem is that validatestring returns the matching string from the cell argument ({'imag',''}) rather than a Boolean indicating if it passes validation. Instead, use strcmp and any:

@(x) any(strcmp(x,{'imag', ''}))

Also, with validatestring, if the input string did not match either 'imag' or '' (actually just 'imag' since empty strings only match in R2014a+), it would throw an error rather than returning false so that the inputParser could return the appropriate error.

Another nice way to fix the problem is to change the syntax of applyFunc entirely so that instead of just 'imag' as an optional string input argument, use a Parameter-Value with 'imag' as the parameter and a validated boolean as the input.

The input definition suggested by Amro in the comments:

p.addParameter('imag', false, @(x)validateattributes(x, {'logical'}, {'scalar'}))

The usage:

mysum(x,'imag',true)
mysum(x)               % default is equivalent to mysum(x,'imag',false)

This would simplify the rest of the code with p.Result.imag being a logical scalar. I would suggest:

x = f(v) + p.Result.imag*1i;
2 of 2
2

The problem is not inputParser, I think the issue is with validatestring.

1) First it does not match on empty strings:

>> x = ''
x =
     ''

>> validatestring(x, {'imag',''})
Expected input to match one of these strings:

imag,

The input did not match any of the valid strings.
Caused by:
    Error using validatestring>checkString (line 85)
    Expected input to be a row vector. 

2) Second, if it successfully matches, it returns the resolved string (from one of the valid choice), instead of true/false. inputParser requires that the validation function either return a boolean, or nothing but throws error on failure.