How do I set default values for functions parameters in MATLAB?
Asked Answered
T

17

136

Is it possible to have default arguments in MATLAB?

For instance, here:

function wave(a, b, n, k, T, f, flag, fTrue=inline('0'))

I would like to have the true solution be an optional argument to the wave function. If it is possible, what is the proper way to do this?

Currently, I am trying what I posted above and I get:

??? Error: File: wave.m Line: 1 Column: 37
The expression to the left of the equals sign is not a valid target for an assignment.
Therm answered 28/4, 2009 at 0:46 Comment(0)
D
159

There isn't a direct way to do this like you've attempted.

The usual approach is to use "varargs" and check against the number of arguments. Something like:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

There are a few fancier things you can do with isempty, etc., and you might want to look at MATLAB central for some packages that bundle these sorts of things.

You might have a look at varargin, nargchk, etc. They're useful functions for this sort of thing. varargs allow you to leave a variable number of final arguments, but this doesn't get you around the problem of default values for some/all of them.

Donne answered 28/4, 2009 at 0:55 Comment(0)
T
60

I've used the inputParser object to deal with setting default options. MATLAB won't accept the Python-like format you specified in the question, but you should be able to call the function like this:

wave(a, b, n, k, T, f, flag, 'fTrue', inline('0'))

After you define the wave function like this:

function wave(a, b, n, k, T, f, flag, varargin)

    i_p = inputParser;
    i_p.FunctionName = 'WAVE';

    i_p.addRequired('a', @isnumeric);
    i_p.addRequired('b', @isnumeric);
    i_p.addRequired('n', @isnumeric);
    i_p.addRequired('k', @isnumeric);
    i_p.addRequired('T', @isnumeric);
    i_p.addRequired('f', @isnumeric);
    i_p.addRequired('flag', @isnumeric);
    i_p.addOptional('ftrue', inline('0'), 1);

    i_p.parse(a, b, n, k, T, f, flag, varargin{:});

Now the values passed into the function are available through i_p.Results. Also, I wasn't sure how to validate that the parameter passed in for ftrue was actually an inline function, so I left the validator blank.

Tierza answered 2/5, 2009 at 12:37 Comment(1)
As best I can tell, this, is the preferred method. It's clean, self-documenting (more so an a bunch of if nargin statemens), easy to maintain, compact, and flexible.Coss
P
22

Another slightly less hacky way is

function output = fun(input)
   if ~exist('input','var'), input='BlahBlahBlah'; end
   ...
end
Prink answered 20/2, 2011 at 15:21 Comment(1)
This option doesn't work if you are going to use MATLAB Coder to generate C code, as Coder does not support the "exist" function.Ampere
M
14

"True" default arguments (i.e. defaults via a purpose-built language feature rather than parsing functions or hand-rolled code) were introduced in 2019b with the arguments block.

As a simplified example, consider the following function:

function myFun(a,b,c)
    arguments
        a
        b
        c = 0
    end
    disp([a b c])
end

c is an optional input with a default value of 0. Inputs a and b have no defaults defined making them required inputs.

myFun may now be called with or without passing a value for c, with the default value of c=0 being used if no value is provided.

>> myFun(1,2)
     1     2     0

>> myFun(1,2,3)
     1     2     3
Manana answered 10/5, 2022 at 20:10 Comment(3)
why no body vote for this answer?Deicide
This answer wasn't a feature in Matlab when the question was originally answered but is now the correct solutionPorett
Sorting the answers by "Trending" finally payed off.Jarrodjarrow
R
11

Yes, it might be really nice to have the capability to do as you have written. But it is not possible in MATLAB. Many of my utilities that allow defaults for the arguments tend to be written with explicit checks in the beginning like this:

if (nargin<3) or isempty(myParameterName)
  MyParameterName = defaultValue;
elseif (.... tests for non-validity of the value actually provided ...)
  error('The sky is falling!')
end

Ok, so I would generally apply a better, more descriptive error message. See that the check for an empty variable allows the user to pass in an empty pair of brackets, [], as a placeholder for a variable that will take on its default value. The author must still supply the code to replace that empty argument with its default value though.

My utilities that are more sophisticated, with many parameters, all of which have default arguments, will often use a property/value pair interface for default arguments. This basic paradigm is seen in the handle graphics tools in MATLAB, as well as in optimset, odeset, etc.

As a means to work with these property/value pairs, you will need to learn about varargin, as a way of inputting a fully variable number of arguments to a function. I wrote (and posted) a utility to work with such property/value pairs, parse_pv_pairs.m. It helps you to convert property/value pairs into a MATLAB structure. It also enables you to supply default values for each parameter. Converting an unwieldy list of parameters into a structure is a very nice way to pass them around in MATLAB.

Rugby answered 28/4, 2009 at 11:56 Comment(0)
Q
7

This is my simple way to set default values to a function, using "try":

function z = myfun (a, varargin)

%% Default values
b = 1;
c = 1;
d = 1;
e = 1;

try 
    b = varargin{1};
    c = varargin{2};
    d = varargin{3};
    e = varargin{4};
end

%% Calculation
z = a * b * c * d * e;
end
Quinine answered 9/6, 2015 at 14:1 Comment(0)
D
6

I am confused nobody has pointed out this blog post by Loren, one of MATLAB's developers. The approach is based on varargin and avoids all those endless and painful if-then-else or switch cases with convoluted conditions. When there are a few default values, the effect is dramatic. Here's an example from the linked blog:

function y = somefun2Alt(a, b, varargin)
% Some function that requires two inputs and has some optional inputs.

% Only want three optional inputs at most
numvarargs = length(varargin);
if numvarargs > 3
    error('myfuns:somefun2Alt:TooManyInputs', ...
        'requires at most three optional inputs');
end

% Set defaults for optional inputs
optargs = {eps 17 @magic};

% Now put these defaults into the valuesToUse cell array,
% and overwrite the ones specified in varargin.
optargs(1:numvarargs) = varargin;
% or ...
% [optargs{1:numvarargs}] = varargin{:};

% Place optional args in memorable variable names
[tol, mynum, func] = optargs{:};

If you still don't get it, then try reading the entire blog post by Loren. I have written a follow-up blog post which deals with missing positional default values. I mean that you could write something like:

somefun2Alt(a, b, '', 42)

and still have the default eps value for the tol parameter (and @magic callback for func of course). Loren's code allows this with a slight, but tricky modification.

Finally, just a few advantages of this approach:

  1. Even with a lot of defaults the boilerplate code doesn't get huge (as opposed to the family of if-then-else approaches, which get longer with each new default value)
  2. All the defaults are in one place. If any of those need to change, you have just one place to look at.

Truth be told, there is a disadvantage too. When you type the function in MATLAB shell and forget its parameters, you will see an unhelpful varargin as a hint. To deal with that, you're advised to write a meaningful usage clause.

Depriest answered 6/4, 2014 at 19:1 Comment(3)
The link to your follow-up blog post is broken; can you fix it?Herminahermine
This answer needs more visibility. I remembered the blog post from Loren, and was looking for it, and opened this stackoverflow question in the hope I would find it easily that way.Cerelia
> The link to your follow-up blog post is broken; can you fix it? <br/> web.archive.org/web/20160711181129/http://all3fox.github.io/…Depriest
K
3

I've found that the parseArgs function can be very helpful.

Here's its documentation:

Helper function for parsing varargin. Makes it easy to write functions that take arguments like this: subaxis(4,2,1,'spacing',0,'marginleft',.1,'H','pt',.1)

ArgStruct=parseArgs(varargin,ArgStruct[,FlagtypeParams[,Aliases]])

  • ArgStruct is the structure full of named arguments with default values.
  • Flagtype params is params that don't require a value. (the value will be set to 1 if it is present)
  • Aliases can be used to map one argument-name to several argstruct fields

example usage:

function parseargtest(varargin)

%define the acceptable named arguments and assign default values
Args=struct('Holdaxis',0, ...
'SpacingVertical',0.05,'SpacingHorizontal',0.05, ...
'PaddingLeft',0,'PaddingRight',0,'PaddingTop',0,'PaddingBottom',0, ...
'MarginLeft',.1,'MarginRight',.1,'MarginTop',.1,'MarginBottom',.1, ...
'rows',[],'cols',[]);

%The capital letters define abrreviations.
% Eg. parseargtest('spacingvertical',0) is equivalent to parseargtest('sv',0)

Args=parseArgs(varargin,Args, ... 
% fill the arg-struct with values entered by the user, e.g.
% {'Holdaxis'}, ... %this argument has no value (flag-type)
% {'Spacing' {'sh','sv'}; 'Padding' {'pl','pr','pt','pb'}; 'Margin' {'ml','mr','mt','mb'}});

disp(Args)
Kerosene answered 28/4, 2009 at 21:0 Comment(2)
Can you elaborate?Thrombus
I've pasted in the documentation. It shows a sketch of how to use it to set default values.Kerosene
D
3

There is also a 'hack' that can be used although it might be removed from MATLAB at some point:

Function eval actually accepts two arguments of which the second is run if an error occurred with the first.

Thus we can use

function output = fun(input)
   eval('input;', 'input = 1;');
   ...
end

to use value 1 as the default for the argument.

Diarist answered 7/12, 2010 at 9:30 Comment(0)
S
3

Here is a nifty way to deal with this issue, taking up only three lines of code (barring line wraps). The following is lifted directly from a function I am writing, and it seems to work as desired:

defaults = {50/6,3,true,false,[375,20,50,0]}; % Set all defaults
defaults(1:nargin-numberForcedParameters) = varargin; % Overload with function input
[sigma,shifts,applyDifference,loop,weights] = ...
     defaults{:}; % Unfold the cell struct
Slash answered 16/1, 2014 at 14:18 Comment(0)
C
2

After becoming aware of ASSIGNIN (thanks to this answer by b3) and EVALIN I wrote two functions to finally obtain a very simple calling structure:

setParameterDefault('fTrue', inline('0'));

Here's the listing:

function setParameterDefault(pname, defval)
% setParameterDefault(pname, defval)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% sets the parameter NAMED pname to the value defval if it is undefined or
% empty

if ~isParameterDefined('pname')
    error('paramDef:noPname', 'No parameter name defined!');
elseif ~isvarname(pname)
    error('paramDef:pnameNotChar', 'pname is not a valid varname!');
elseif ~isParameterDefined('defval')
    error('paramDef:noDefval', ['No default value for ' pname ' defined!']);
end;

% isParameterNotDefined copy&pasted since evalin can't handle caller's
% caller...
if ~evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')'])
    callername = evalin('caller', 'mfilename');
    warnMsg = ['Setting ' pname ' to default value'];
    if isscalar(defval) || ischar(defval) || isvector(defval)
        warnMsg = [warnMsg ' (' num2str(defval) ')'];
    end;
    warnMsg = [warnMsg '!'];
    warning([callername ':paramDef:assigning'], warnMsg);
    assignin('caller', pname, defval);
end

and

function b = isParameterDefined(pname)
% b = isParameterDefined(pname)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% returns true if a parameter NAMED pname exists in the caller's workspace
% and if it is not empty

b = evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) ;
Canzonet answered 22/3, 2011 at 9:55 Comment(0)
A
1

This is more or less lifted from the MATLAB manual; I've only got passing experience...

function my_output = wave ( a, b, n, k, T, f, flag, varargin )
  optargin = numel(varargin);
  fTrue = inline('0');
  if optargin > 0
    fTrue = varargin{1};
  end
  % code ...
end
Afoot answered 28/4, 2009 at 0:59 Comment(3)
There were a couple of errors in the code that I corrected. First, "optargin" needs to be defined. Second, "varargin" is a cell array that collects all subsequent inputs, so you have to use cell array indexing to remove values from it.Ebracteate
I need to get my vision checked; I swear I saw none of that in the manual yesterday :(Afoot
@kyle: Not to worry, we all make mistakes. That's why I like SO's wiki-ish style: if I make some silly typo, there's usually someone else around who can catch it and fix it quickly for me. =)Ebracteate
R
1

Matlab doesn't provide a mechanism for this, but you can construct one in userland code that's terser than inputParser or "if nargin < 1..." sequences.

function varargout = getargs(args, defaults)
%GETARGS Parse function arguments, with defaults
%
% args is varargin from the caller. By convention, a [] means "use default".
% defaults (optional) is a cell vector of corresponding default values

if nargin < 2;  defaults = {}; end

varargout = cell(1, nargout);
for i = 1:nargout
    if numel(args) >= i && ~isequal(args{i}, [])
        varargout{i} = args{i};
    elseif numel(defaults) >= i
        varargout{i} = defaults{i};
    end
end

Then you can call it in your functions like this:

function y = foo(varargin)
%FOO 
%
% y = foo(a, b, c, d, e, f, g)

[a, b,  c,       d, e, f, g] = getargs(varargin,...
{1, 14, 'dfltc'});

The formatting is a convention that lets you read down from parameter names to their default values. You can extend your getargs() with optional parameter type specifications (for error detection or implicit conversion) and argument count ranges.

There are two drawbacks to this approach. First, it's slow, so you don't want to use it for functions that are called in loops. Second, Matlab's function help - the autocompletion hints on the command line - don't work for varargin functions. But it is pretty convenient.

Rover answered 13/5, 2009 at 4:18 Comment(1)
Please don't edit this answer to put "MATLAB" in all caps. I realize that's the official styling for it, but it seems like shouting to me, so I don't use it in my own writing.Rover
T
1

If you would use Octave you could do it like this - but sadly MATLAB does not support this possibility:

function hello (who = "World")
  printf ("Hello, %s!\n", who);
endfunction

(Taken from the documentation.)

Tearjerker answered 10/6, 2014 at 14:9 Comment(0)
A
0

You might want to use the parseparams command in MATLAB; the usage would look like:

function output = wave(varargin);
% comments, etc
[reg, props] = parseparams(varargin);
ctrls = cell2struct(props(2:2:end),props(1:2:end),2);  %yes this is ugly!
a = reg{1};
b = reg{2};
%etc
fTrue = ctrl.fTrue;
Affusion answered 8/10, 2010 at 19:4 Comment(0)
C
0
function f(arg1, arg2, varargin)

arg3 = default3;
arg4 = default4;
% etc.

for ii = 1:length(varargin)/2
  if ~exist(varargin{2*ii-1})
    error(['unknown parameter: ' varargin{2*ii-1}]);
  end;
  eval([varargin{2*ii-1} '=' varargin{2*ii}]);
end;

E.g., f(2,4,'c',3) causes the parameter c to be 3.

Canzonet answered 11/10, 2010 at 13:56 Comment(0)
F
0

I like to do this in a somewhat more object-oriented way.

Before calling wave(), save some of your arguments within a struct, e.g. one called parameters:

parameters.flag = 42;
parameters.fTrue = 1;
wave(a, b, n, k, T, f, parameters);

Within the wave function then check, whether the struct parameters contains a field called 'flag' and if so, if its value is non empty. Then assign it either a default value you define before, or the value given as an argument in the parameters struct:

function output = wave(a, b, n, k, T, f, parameters)
  flagDefault = 18;
  fTrueDefault = 0;
  if (isfield(parameters,'flag') == 0 || isempty(parameters.flag)), flag=flagDefault;else flag=parameters.flag; end
  if (isfield(parameter, 'fTrue') == 0 || isempty(parameters.fTrue)), fTrue=fTrueDefault;else fTrue=parameters.fTrue; end
  ...
end

This makes it easier to handle large numbers of arguments, because it does not depend on the order of the given arguments. That said, it is also helpful if you have to add more arguments later, because you don't have to change the functions signature to do so.

Fransis answered 24/5, 2018 at 12:4 Comment(2)
Why not follow the MATLAB standard of name-value pairs? wave(a,b,'flag',42,'fTrue',1)Caniff
This is certainly an option as well, especially when one has only few parameters. Calling wave() with a big number of name-value pairs, however, might reduce the readability of the code. I therefore often prefer to group certain inputs into structs.Fransis

© 2022 - 2024 — McMap. All rights reserved.