views:

5461

answers:

8

Hello.

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, can anyone demonstrate 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.

Thanks!

+11  A: 

As far as I know, 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 args. 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.

[update] glad that helped.

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.

simon
This worked! Thanks! It's too bad defaulting arguments can't be done more elegantly.
Scott
@Scott: Never say things can't be done! See http://blogs.mathworks.com/pick/2010/04/02/setting-default-values/
Richie Cotton
+1  A: 

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
kyle
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.
gnovice
I need to get my vision checked; I swear I saw none of that in the manual yesterday :(
kyle
@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. =)
gnovice
+3  A: 

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 inputing 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.

woodchips
+1  A: 

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

Mr Fooz
+3  A: 

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 left the validator blank.

Matt
A: 

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.

Andrew Janke
A: 

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;
shabbychef
A: 
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.

Tobias Kienzler