7
$\begingroup$

I have a function with a number of arguments, but some of them are optional.

1.) If when the function is called, some are left empty, how do I code it so that it defaults to a specific value?

2.) What if of 5 arguments, 3 are optional, how can the code recognize which one to set to default? For example:

function [u, v] = somefxn(required, required2, optional, optional2, optional3)

and say when I call this function, only optional2 is filled.

Update: Is there something I can use that says

if optional2 is empty
    return default_value
end
$\endgroup$
8
  • $\begingroup$ Do you mean "empty" as in optional2=[] or as in somefxn(required,required2,optional,optional3)? $\endgroup$ Commented Dec 30, 2012 at 21:12
  • $\begingroup$ @ChristianClason I suppose the second one, but aren't they the same? $\endgroup$ Commented Dec 30, 2012 at 21:23
  • 1
    $\begingroup$ They're not -- an empty variable as argument is not the same as a missing argument. Since the argument names are local to the function, Matlab has no way of telling whether the second or the third optional argument is missing. If you require arguments that are independent of their order, you need to implement key/value pairs. A rather elegant way is described in this answer on SO. $\endgroup$ Commented Dec 30, 2012 at 21:26
  • 1
    $\begingroup$ The answer is indeed (as usual for SO) rather compact... Unfortunately, there's no simpler way to make Matlab do something it was not designed to do. If you really(!) need to account for missing arguments, your best bet is to adapt the SO answer (you just need to replace the line option=... with the full(!) list of expected arguments); otherwise you should follow Nat Wilson's edited suggestion (which is how most Matlab commands such as gmres work, in fact). $\endgroup$ Commented Dec 30, 2012 at 23:26
  • 2
    $\begingroup$ You can do this in a slightly more elegant way (though that's a matter of taste) using inputParser(). One example is here (just look at the setup_params() function starting on line 178). $\endgroup$ Commented Dec 31, 2012 at 13:47

4 Answers 4

7
$\begingroup$

Here's one take:

1) In Matlab, if you use varargin, then you must provide all preceding optional arguments (that is, optional must be given as well as optional2). In this case (for example, if you call somefxm(myarg, myarg2, myoptarg, myoptarg2), then you know based on the length of varargin (2) that only optional3 needs a default applied. You can have an if statement that says something like

if length(varargin) == 2
    optional3 = 3;  % or whatever
end

You can have additional conditional statements to handle having only one optional argument (e.g. length(varargin) == 1) or no optional arguments (e.g. length(varargin) == 0).

2) Note that with this scheme, Matlab has no clever way of knowing which function argument fits into which option, so you must keep everything in sequential order. If you need more flexibility, you can do something sort of like keyword arguments by preceding the argument with a descriptive string, which is the way that some common functions like plot work. Then you either need to write logic to parse varargin (as in Christian Clason's comment), or you can use the inputParser object.

edit

Another (in my opinion, clunkier) way of treating an "empty" optional2 is to test whether the provided argument is simply an empty matrix, with

if isempty(cell2mat(varargin(2))
    optional2 = 3; % or whatever
end

Then, you could call somefxn with an "empty" second optional argument as:

somefxn(myarg, myarg2, myoptarg, [], myoptarg3)

Then, the second optional argument will be assigned whatever you've coded into the function. If you do this, you need to make sure that an empty matrix is not an otherwise valid argument to somefxn, otherwise you'll have just overloaded the proper behaviour.

$\endgroup$
1
  • 3
    $\begingroup$ You can also use nargin (and nargout) instead of length(varargin) (and length(varargout)) if you know the number of optional arguments beforehand. $\endgroup$ Commented Dec 30, 2012 at 10:55
9
$\begingroup$

You can do this in a way that isn't as prone to breaking when the order of the arguments changes using inputParser(), which also allows you to validate the arguments.

One example is here (just look at the setup_params() function starting on line 178). More documentation with examples is here.

$\endgroup$
3
$\begingroup$

Input parameter handling in Matlab is just really annoying. This works:

function out = foobar(foo, bar, baz)
    if ~exist('baz', 'var') ||  isempty(baz)
        baz = 'default_value';
    end

This needs to be repeated for all optional input parameters. Pro: it also does not depend on the order of the parameters in the function definition. Another option are all the nargin hacks:

if nargin < 3 || isempty(baz)
    baz = 'baz';
    if nargin < 2 || isempty(bar)
        bar = 'bar';
        if nargin < 1 || isempty(foo)
             foo = 'foo';
        end
    end
 end

Obviously this is ugly and not very extensible; plus it is dependent on the definition order of the parameters.

The last option might be inputParser, but I have no idea how you can easily do the 'isempty' part with it. I can't find this type of input handling in the example posted by @DavidKetcheson.

Edit: @FedericoPoloni mentions another alternative: option structures. I think they are okay if you have many input parameters (and if you throw an error if an unknown field name is parsed to circumvent the confusion FredericoPoloni mentions). I would use something like this :

function test(foobar, opts)

default_opts.foo = 'foo';
default_opts.bar = 'bar';

if nargin > 1
    opts = parse_opts(default_opts, opts);
end

And as a separate function:

function parsed_opts = parse_opts(default_opts, in_opts)

in_fields = fieldnames(in_opts);
n_in_fields = numel(in_fields);

parsed_opts = default_opts;

for i_field = 1:numel(in_fields)
    cur_field = in_fields{i_field};

    if isfield(default_opts, cur_field)
        parsed_opts.(cur_field) = in_opts.(cur_field);
    else
        error('parse_opts:input', 'Unknown field name `%s`', cur_field);
    end
end
$\endgroup$
1
  • $\begingroup$ +1 for the first method. By far the most readable and fastest to code/modify. $\endgroup$ Commented May 24, 2014 at 11:32
0
$\begingroup$

Let me add to the list another method that is used a lot in Matlab but that I do not recommend, to point against it: options structures.

Basically, your syntax requires an additional options struct opts, and you check for the presence of specific fields. Example:

>> options.TolX=1-e-3;
>> x=fzero(fun,x0,options)

% in fzero.m
function x=fzero(fun,x0,options)
if not(isfield(options,'TolX'))
    tol=defaultTolerance;
else
    tol=options.TolX;
end

This is what is used in several standard Matlab methods, for instance fzero that I used for this example.

The main reason why you should not do it is that error checking is terrible: if you have a field options.tolX (missing capital T), things will often go silently wrong.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.