Loren on the Art of MATLABTurn ideas into MATLAB

This is machine translation

Translated by
Mouseover text to see original. Click the button below to return to the English version of the page.

Nice Way to Set Function Defaults37

Posted by Loren Shure,

Last week, I wrote a post on the switch statement in MATLAB. One theme in the comments was about using switch (or not!) for setting default values for input arguments that users didn't initialize. I realized that there is a nice pattern for setting these values that uses some compact, but readable code.

Function Defaults

Sometimes I want to write a function that has some required inputs and some optional trailing arguments. If the arguments are specified by their order, and not by parameter-value pairs, there is a nice way to accomplish this take advantage of varargin. Note that neither of these methods checks the validity of the overridden elements.

Suppose my function requires the first 2 inputs, but there are 3 others that the user can choose to set, or allow them to take default values. In this scenario, once they choose to set an optional input, they must set all the optional ones that precede it in the argument list. Here's an example function header.

dbtype somefun2 1
1     function y = somefun2(a,b,opt1,opt2,opt3)



Here's another way I could write this function header, using varargin.

dbtype somefun2Alt 1
1     function y = somefun2Alt(a,b,varargin)



Setting Default Values

To set default values in somefun2, I could use a switch statement or use if-elseif constructs. Here I chose to use a switch statement.

type somefun2
function y = somefun2(a,b,opt1,opt2,opt3)
% Some function with 2 required inputs, 3 optional.

% Check number of inputs.
if nargin > 5
error('myfuns:somefun2:TooManyInputs', ...
'requires at most 3 optional inputs');
end

% Fill in unset optional values.
switch nargin
case 2
opt1 = eps;
opt2 = 17;
opt3 = @magic;
case 3
opt2 = 17;
opt3 = @magic;
case 4
opt3 = @magic;
end



The code is verbose and, in my opinion, not very pretty. It's also error-prone. If I decide to change a default setting for one value, I have to update each relevant case. What a drag!

Here's a way to set the defaults in one location and then overwrite the ones the user specified.

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

% only want 3 optional inputs at most
numvarargs = length(varargin);
if numvarargs > 3
error('myfuns:somefun2Alt:TooManyInputs', ...
'requires at most 3 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{:};



First I place the default optional values into a cell array optargs. I then copy the cells from varargin to the correct cells in optargs and I have overridden the defaults. I have only one place where the default values are set, and the code doesn't grow dramatically in length as I add additional optional inputs. Finally, I spread out the cells from varargin into well-named individual variables, if I want to. Since each element in a cell array is its own MATLAB array, and MATLAB has copy-on-write behavior, I am not creating extra copies of these optional inputs (see this post for more information).

Other Methods for Dealing with Optional Inputs

There are other methods for dealing with optional inputs. These include specifying parameter-value pairs. With or without such pairs, you can use inputParser to help set the values you use. You can specify the optional input in a struct, with fields containing the various options, and you can use cell arrays, but then you have to decide how to structure and specify the contents.

Your Techniques for Specifying Optional Values

Do you have a technique for specifying optional values that works well for you? Please share with us here.

Get the MATLAB code

Published with MATLAB® 7.8

Note

Cris Luengo replied on : 1 of 37
Nice! I think I won't use my old way of setting defaults any more! This is what I used to do: function y = somefun2(a,b,opt1,opt2,opt3) if nargin<3 opt1 = 1; end if nargin<4 opt2 = 2; end if nargin<5 opt3 = 3; end I like your way a lot better!
Scott Hirsch replied on : 2 of 37
I'll second Cris! I use varargin, but my code still looks pretty much like Cris' example (most of it on the File Exchange for the world to see). I love this elegant approach of just swapping out the contents of a cell array. Thanks, Loren!
Loren replied on : 3 of 37
Theirry- inputParser was introduced in R2007a, MATLAB 7.4. You can find information like this in the release notes. --Loren
Gautam Vallabha replied on : 4 of 37
I prefer to use EXIST with explicitly listed parameters in the function definition line.
function myfcn(a,b,tol,mynum,func)
if ~exist('tol','var'), tol = eps; end
if ~exist('mynum', 'var'), mynum = 17; end
...

With varargin and nargin, I have to change multiple lines to add a new optional parameter or change the order of parameters. It also becomes tricky to allow uses like myfcn(100, 200, eps, [], @rand) where the [] means that the function should assign the default value for mynum. With the EXIST test, it becomes straightforward:
if ~exist('mynum','var') || isempty(mynum),
mynum = 17;
end

Steve Eddins replied on : 5 of 37
I'll echo Chris and Scott. I usually write it the way Chris showed, but I think I like your cell array manipulation better.
Amy replied on : 6 of 37
The cell array approach is rather clever. However, the problem with using the varargin is that you aren't able to get useful function hints for your functions (introduced in 2008b); you end up with ... in place of varargin. That's why I've started writing code similar to the example Cris showed except that I usually do if nargin<3 || isempty(opt1) opt1 = 1; end to allow the user to specify opt1 as empty to use the default value and still specify additional opts. I use nargin because using exist takes a longer to execute.
Kent Conover replied on : 7 of 37
I use a function to determine whether a variable exists in the workspace. If the variable is not defined then it is set to a default. For example if isundefined('mount_col') mount_col = 'TOKEN NUMBER'; end Here is the function "isundefined.m" function tf = isdefined(in_var_name) %% tf = isdefined(in_var_name) % % Returns a logical indicating if the variable "in_var_name" both exists and is % not empty in the "caller" workspace. % % "in_var_name" is a text string that specifies the name of the variable to search for. % % Kent Conover, 12-Mar-08 cmd_txt = ['exist(''',in_var_name, ''', ''var'');']; if evalin('caller', cmd_txt); cmd_txt = ['~isempty(',in_var_name, ');']; if evalin('caller', cmd_txt); tf = true; else tf = false; end else tf = false; end
Loren replied on : 8 of 37
Amy- You are right about function hints. Kent- Your code seems to depend on naming the variables in the caller the same as the names in the actual function definition. Seems a bit fragile for my taste. --Loren
Thierry Dalon replied on : 9 of 37
I did not know the function inputParser! It is not available in R14SP3 but in R2008a; when was it introduced? There also some interesting contributions on the topic in the FEX: - parse_pv_pairs: https://www.mathworks.com/matlabcentral/fileexchange/9082-parse-pv-pairs - parseargs: https://www.mathworks.com/matlabcentral/fileexchange/10670-parseargs--simplifies-input-processing-for-functions-with-multiple-options - parseArgs : #3448 - checkfield: #17441 all with plus and minus. I am not sure inputParser aggregates features of all FEX contributions, like use of aliases, abbreviations, feasible values etc. I would have to check... Thanks anyway for dealing with this topic which is quite important as soon as you start programming a little bit in Matlab!
Ben replied on : 10 of 37
We use this approach in many places throughout our 100k line MATLAB codebase, a colleague originally came up with it. Some functions we have written over time have many, many, options and so we specify the default values with a structure in the beginning of the file. The settings we wish to override are contained in the input 'settings' structure, and at the end, we use the wonderful setstructfields() function (which comes from MATLAB; I am unsure if it comes from a toolbox) to override the values in defaults with those contained in settings, and then dump the structure into the workspace using a custom function struct2workspace() which basically runs assignin('caller','var',value) on each member of settings. (Although we could just leave it there and dereference all the items right from the settings structure.) It kind of messes with what MLINT wants to do in terms of code analysis, but it's a great tool for us, so that sane defaults are recorded right in the file where they are used and not elsewhere. In some cases we have multiple levels of this going on and I have no idea how we'd do without it - many of our functions have a sizable number of options, possibly because this approach has made it manageable. function out = funcname(arg1,arg2,settings) defaults.variable1 = val_1; %define default values defaults.variable2 = val_2; defaults.variable3 = val_3; ... % Overwrite defaults with specified settings (if any) settings = setstructfields(defaults,settings); struct2workspace(settings); %optional
Daniel replied on : 11 of 37
I join the Chris team as well. But the cell-array approach was really nifty. As for the loss of function hints when using varargin, I unfortunately have to say that the function hints have been a dissapointment to me. They take far too long to pop up, and unless you type really carefully, they seem to dissapear. Now, if there was a button you could press to force matlab to display the function hints, (like the tab in tab completion) maybe I would start using them..... --DA
Joe Kirk replied on : 12 of 37
Nice Loren! I like your method quite a bit and will probably start using it more often. I have used Chris' method in the past, but more recently started using SWITCH statements, except that I wrap it in a FOR loop to eliminate redundant default settings. For example:

function varargout = tsp_ga(xy,dmat,pop_size,num_iter,show_prog,show_res)

% Process Inputs and Initialize Defaults
nargs = 6;
for k = nargin:nargs-1
switch k
case 0
xy = 10*rand(50,2);
case 1
N = size(xy,1);
a = meshgrid(1:N);
dmat = reshape(sqrt(sum((xy(a,:)-xy(a',:)).^2,2)),N,N);
case 2
pop_size = 100;
case 3
num_iter = 1e4;
case 4
show_prog = 1;
case 5
show_res = 1;
otherwise
end
end

I'm not sure how I could make your method work in the case of the distance matrix (dmat) input, because it's size depends on the number of xy points. In other words, I don't have a way to set the default for the second input without knowing what the first input is.
Loren replied on : 13 of 37
Joe- It's true you couldn't set dmat on the first pass. It would have to be after doing all the other default setting so you could be sure of the first value. You could still set all the rest first with the cell technique, I think. --Loren
Yair Altman replied on : 14 of 37
I use a variation of the method Ben mentioned in comment #10 above. Basically, I set a structure of default values at the top of the code. This is highly readable/maintainable since the struct field names immediately convey the meaning, as opposed to a cell array in which separate elements might be misunderstood or swapped by mistake. I then use a loop over the input arguments and update the specified struct field. The input args are expected in the usual Matlab P-V notation (..., 'paramName',paramValue, ...) and can therefore be specified in any order (another usability benefit). Unexpected parameter names cause an error to be displayed. Adding new parameters to this template is extremely easy, helping code maintainability and reuse. Here's a parred-down snippet from my recent UISplitPane submission on the File Exchange:
%% Process optional arguments
function paramsStruct = processArgs(varargin)

% Get the properties in either direct or P-V format
[parent, pvPairs] = parseparams(varargin);

% Now process the optional P-V params
try
% Initialize with default values
paramName = [];
paramsStruct.dividercolor = '';
paramsStruct.dividersize = 5;
% other default params can be specified here

supportedArgs = {'orientation','parent','tooltip',...
'dividerwidth','dividercolor','dividerlocation',...
'dividerminlocation','dividermaxlocation'};

while ~isempty(pvPairs)

% Ensure basic format is valid
paramName = '';
if ~ischar(pvPairs{1})
error('invalidProperty','Invalid property');
elseif length(pvPairs) == 1
error('noPropertyValue',['No value specified for property ''' pvPairs{1} '''']);
end

% Process parameter values
paramName  = pvPairs{1};
paramValue = pvPairs{2};
%paramsStruct.(lower(paramName)) = paramValue;  % good on Matlab7, no good on Matlab6...
paramsStruct = setfield(paramsStruct, lower(paramName), paramValue);  %#ok Matlab6
pvPairs(1:2) = [];
if ~any(strcmpi(paramName,supportedArgs))
url = ['matlab:help ' mfilename];
urlStr = getHtmlText(['<a href="' url '" rel="nofollow">' strrep(url,'matlab:','') '</a>']);
error('invalidProperty',...
['Unsupported property - type "' urlStr ...
'" for a list of supported properties']);
end
end  % loop pvPairs

catch
if ~isempty(paramName)
paramName = [' ''' paramName ''''];
end
error('invalidProperty',['Error setting uisplitpane property' paramName ':' char(10) lasterr]);
end
end

In the code body, I simply check or use the value of paramsStruct.ParameterName. So simple. Note: the code uses Matlab's built-in parseparams function to separate the PV argument pairs. This step can easily be done without resorting to parseparams, which is simply a convenience function.
Kieran Parsons replied on : 15 of 37
I use a variation on the inputparser theme. Some of the driving factors for me with complicated function input arguments are: 1) Setting of defaults. 2) Checking of values against some kind of basic check (anonymous function). 3) Clear help about the params. So at the top of my function would be something like:
function my_func(varargin)

parser = my_custom_input_parser();
% Format:
%  param_name ...
%  default, ...
%  test_function, ...
%  ‘One line help’, ...
%  ‘Multiline help’.');

‘param1’, ...
[1 2 3], ...
@isnumeric, ...
‘One line help’, ...
‘Multiline help’.');

% Check if help should be displayed ('help' is the input) and exit if so.
if parser.display_help_if_req(varargin{:});
return;
end
p = parser.parse(varargin{:}); % p is a struct

end

This allows default setting, testing of values, and easy (but non-standard) help mechanism. I like the inputparser approach of supporting either PV pairs or a struct + PV pairs. I also have a fairly simple method of the custom input parser to generate an html help page of the input arguments. As more of my code is moving towards object-oriented classes I have adapted this procedure for class properties. In order to do this I generate a “parameters” class and use inheritance to bring these properties into my class. I know that Matlab can use dynamic properties but I have found these to be quite slow for get/set access. By “generate” I mean that the parameters class code is automatically generated (ie I only need to write the template) using part of the help for the class (which makes it very easy for other members of my team to use the same procedure for their classes). For example, the “functional” class would be something like:
classdef my_class < my_class_params
%MY_CLASS is a class with the following parameters.
%
% Parameters:
%   param1 = One line help for param1
%     Multiline help.
%     Default = [1 2 3]
%     Basic test = @isnumeric
%
%   param2 = One line help for param2
%     Multiline help.
%     Default = [1 2 3]
%     Basic test = @isnumeric
%

methods (Access = public)
function this = my_class(varargin)
% Varargin can contain PV pairs, a struct + PV pairs, or a my_class_params object + PV pairs.
this = this@ my_class_params(varargin{:});
end
end
end

All the defaults, help, basic checks are now very visible in “my_class” and accessible to the normal help/doc functions or the html page version. If anything changes for these (or at startup) I rerun the function I have that parses these files and generates the my_class_params.m file using a template (via the excellent m2html package). One additional advantage of the class generation is that I can add “compile-time” options. For example I have 2 templates, one that includes all the parameter checking in the my_class_params, and one that does not (and is faster). It’s like an “assertions on/off” debug flag that Matlab unfortunately does not have. Not simple to say the least, but it’s quite effective.
Matt Fig replied on : 16 of 37
Loren, I have only recently started using what I would call, now that I see your method, a hybrid method. It is less error prone than assigning a new default in each switch case, and less verbose than that method as well. Here is an example:
 

function y = somefun2(a,b,tol,mynum,func)
% Some function with 2 required inputs, 3 optional.

% Check number of inputs.
if nargin > 5
error('myfuns:somefun2:TooManyInputs', ...
'requires at most 3 optional inputs');
end

defaults = {eps, 17, @magic};  % Store defaults, change them here only.

% Fill in unset optional values.
switch nargin
case 2
[tol mynum func] = defaults{:};
case 3
[mynum func] = defaults{2:3}
case 4
func = defaults{3};
end

 
I think I like this better when there are only a few optional arguments. As the number of optional arguments gets larger, the function declaration line becomes too ugly for me. In this case I think I would go with using varargin. Great article! Thanks.
Loren replied on : 17 of 37
Nice, Omid. You've sort of stolen my thunder for next week's post, but oh well! Great minds :-) ... --Loren
Martin replied on : 18 of 37
I share the concerns of Gautam Vallabha about passing empty arguments in the varargin. The following changes to the code makes it possible to use: somefun2Alt(a,b) somefun2Alt(a,b,[],1) somefun2Alt(a,b,[],[],1) function y = somefun2Alt(a,b,varargin) % Some function that requires 2 inputs and has some optional inputs. % only want 3 nonempty optional inputs at most numvarargs = find(~cellfun('isempty',varargin)); if length(numvarargs) > 3 error('myfuns:somefun2Alt:TooManyInputs', ... 'requires at most 3 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(numvarargs) = varargin(numvarargs); % Place optional args in memorable variable names [tol, mynum, func] = optargs{:}; y = {a b tol mynum func};
Omid replied on : 19 of 37
-Martin I wrote a tiny ad hoc function, findnull above, to do the trick. Soon after that cellfun popped up in my head but you'd taken care of my "blunder" alright. In your code snippet, we could drop the "find" to let logical indexing kick in - this is actually an mlint suggestion - and replace the string function name 'isempty' with a function handle @isempty; In addition to the well-known advantages of the latter to the former (in this simple case it's not obvious but one would be performance: each time a search is not required to find the function referenced by a handle), there are cases when string function names would be a headache. One that I have experienced, when dealing with legacy code, is when the program is to be compiled; mcc will not "see" the functions referenced using strings and they must be supplied explicitly. (This happens even if str2func is used to construct handles from string names.) For a very beautiful usage of function handles, and the scope intricacies associated with these "data types" when they're defined in a (sub)function and used in another function, I really recommend taking a look at John D'Errico's loopchoose (FEx ID 13276). -Loren I'm sorry; I didn't mean to! But I'm sure your post will, as always, bring up something nifty. Can't wait to read it.
Omid replied on : 20 of 37
Nice use of cell arrays, Loren! As for what Gautam Vallabha replied about this becoming tricky when dealing with [] in the arguments, one could simply use a function like findnull (below) to take care of default value assignment when [] is passed in.
 

function somefcn(reqArg1,reqArg2,varargin)

% Usual checks for number of arguments...

% Beautifully, being a cell array, optArgs can accommodate structures (to pass options to an optimization solver, for example), function handles (to choose a particular optimization solver, for example) etc.

optArgs   = {1,2,3};
nullArgs  = findnull(varargin);
[optArgs{~nullArgs}] = varargin{~nullArgs};

% ...

function ind = findnull(a)
a     = a(:);
len_a = length(a);
ind   = false(len_a,1);
for ctr = 1:len_a
if isequal(a{ctr},[]), ind(ctr) = true; end
end

 
Martin replied on : 21 of 37
Omar, I agree about the logical indexing. I was not aware of the issues with the function handle, so thanks for pointing that out!
Yair Altman replied on : 22 of 37
Omar & Martin - cellfun(@isempty,...) may be better for the compiler, but it is actually *Worse* than cellfun('isempty') for performance. This is indeed counter-intuitive (and undocumented) but true. The reason appears to be that using 'isempty' (as well as the other predefined string functions ('isreal', 'islogical', 'length', 'ndims', 'prodofsize') uses specific code-branches optimized for performance (at least as of R2007b - I haven't yet tested this on newer releases):  >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.115583 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 7.493989 seconds.  Now, the obvious solution would be for the internal Matlab code to check for function-handle equality and use the optimized version if possible. Perhaps a future Matlab release will do this. Hint hint MTW? :-) Yair Altman
Loren replied on : 23 of 37
Yair- We could improve cellfun to check function handles to see if they match specified strings. Even then MATLAB would have to be careful in case the user has overridden the built-in version of whatever the string points to. --Loren
Omid replied on : 24 of 37
Yair- What can I say! That was indeed "counter-intuitive (and undocumented) but true." I applied a generally true statement to something that turned out to be a special case! Thanks for pointing this out. I tested this in R2008a and R2008b. The difference is actually an order of magnitude! R2008a >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.024467 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.929305 seconds. R2008b >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.014660 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.557050 seconds. (These timings are after some warm up - I didn't use Steve Edins' timeit so that the results can be directly compared with what you reported for R2007b.) -Omid PS. Yair and Martin- You've both written my name as Omar, which is strange given that the last two letters are totally different!
Kent Conover replied on : 25 of 37
Hi Loren, Thanks for replying to my post: # Loren replied on May 5th, 2009 at 20:17 UTC : Kent- Your code seems to depend on naming the variables in the caller the same as the names in the actual function definition. Seems a bit fragile for my taste. –Loren However, I am unsure about your concern. Perhaps my example was unclear. But to address your point, I have no problem calling such functions with different variable names in the caller function. Say func1 is defined thus: function x = func1(y) if isundefined('y') y = 1; end x = 2*y; Then func1 can be called like this: >>z = 2; >>func1(z) ans = 2 Moreover, this function works even if z is empty or absent. ie: >>clear z >>func1(z) ans = 2 or >>func1() ans = 2 So, I can't see your point about fragility, unless you are concerned about maintaining the order and position of the parameters passed - in which case you have me!. I keep the number of passed parameters <= 6. Nevertheless, I value your perspective, and I would appreciate knowing any further thoughts that you have on this issue. Cheers! -Kent
Loren replied on : 26 of 37
Kent- I think I misunderstood your code. I thought it depended on names being the same. Clearly not true. --Loren
Bryan Reed replied on : 27 of 37
I was about to post my method, but I saw that Gautam Vallabha already posted it, absolutely verbatim! The code fragment "~exist('varname','var') || isempty(varname)" appears all over the place in functions I've written over the past few years. I find this method to be extremely concise, readable, and flexible. You can change the order or number of parameters in the function definition and it doesn't change the code for setting defaults. I don't know that it has any downsides, apart from the case where you need varargin because the user can supply an unlimited number of options. Typically I'll only use varargin for handing options down to a lower-level built-in function, for example if the function I'm writing is basically a wrapper for MATLAB's plot() function. Then the user can specify line types and colors etc., and I as the programmer don't have to think about how that would work.
Matt replied on : 28 of 37
Loren, Thanks for the write-up. In my opinion, inputting/outputting variables to a function is the bane of coding in any language. Everyone has their own opinion on how it should be done, and none of them work all that well apart, let alone together when you integrate code. This is an especially a large problem when using a development coding environment like MATLAB as not much is ever polished when it gets used. I am pleased to see the inputParser function added to the default framework though. Great step in the right direction for elegant and functional parsing of an input stream! As a user of the Python module pyparsing, I have seen first hand how creating a scheme for your parser can pay dividends on code flexibility, simplicity, and readability. I suggest you revisit this same exercise using inputParser to put the virtues on the 'big stage'. -Matt
David replied on : 29 of 37
Hi Loren, I discovered inputParser a few months ago and am delighted. However, I'd like to be able to change some of the values of passed arguments within the function as sometimes the default values of input parameters depends on the value of other input paramters. For example, in the function below, the default size of the moving average window depends on the size of the data being smoothed. To do this, I create a new variable called "wind_size." However, I'd rather modify the value of p.Results.wind_size so that I have less variables to keep track of. When I try to do this however, I get the following error message: "??? Setting the 'Results' property of the 'inputParser' class is not allowed." Is there a way to get around that limitation? much thanks, -David
function outdata=movavg(indata,varargin)
%Smooths indata with a boxcar windowed moving average

p=inputParser;

p.parse(indata,varargin{:});

if isempty(p.Results.wind_size)
wind_size=round(length(indata)/20);
else
wind_size=p.Results.wind_size;
end

if wind_size<1,
wind_size=1;
end

n_outdata=length(indata)-wind_size+1;
outdata=zeros(1,n_outdata);
for a=1:n_outdata,
outdata(a)=mean(indata(a:a+wind_size-1));
end


Loren replied on : 30 of 37
Hi David- Not that I know of. You might use the link on the right to request an enhancement with technical support. --Loren
Nio replied on : 31 of 37
Hi David, I guess this comes too late, but anyway here's a work around to your problem. You could extract the p.Results structure from your inputParser object:
p_res = p.Results;

Now you have a simple structure 'p_res' that can be modified as usual. Maybe this works for you. - Nio
Zhenyu He replied on : 32 of 37
optargs(1:numvarargs) = varargin;

from your previous function somefun2 I saw that
switch nargin
case 2
opt1 = eps;
opt2 = 17;
opt3 = @magic;
case 3
opt2 = 17;
opt3 = @magic;
case 4
opt3 = @magic;
end

It seems that func is the argument if you only add one argument in the input and you put the argument func at last. So I think it should be
optargs(3-numvarargs+1:end) = varargin;

Or, the argument should be in reverse order
[func, mynum, tol] = optargs{:};

-Zhenyu
Loren replied on : 33 of 37
Zhenyu- func is meant to be the final optional argument, otherwise @magic is used. It's possible I'm missing something, but I think things are in the right order. --loren
Erzieher60 replied on : 34 of 37
This page comes up fairly high on a google search for "matlab function defaults", so it seems plenty of people will be looking here for methods to try. I am a fan of the 'varargin' method:
function foobar(varargin)
Defaults = {A,B,C...};
Defaults(1:nargin) = varargin;

- Two lines of short and readable code. - Works with any data types or functions. - Does not unnecessarily increase the cyclomatic (McCabe) complexity value. - Is much much quicker than calling 'exist', 'isempty' or the like. - Assigning, reassigning or using values requires careful attention to order. Be careful! - The number of input arguments can also be more than the number of default values. The cell array 'Defaults' will have at least as many cells as there are input variables, but will contain no less than those that are defined as function defaults. Very useful, on occasion where a minimum number of defaults need to be set. - Empty values may be replaced with defaults using:
function foobar(varargin)
Defaults = {A,B,C...};
Inds = find(cellfun(@isempty,varargin));
varargin{Inds} = Defaults{Inds};
Defaults(1:nargin) = varargin;

but this is slower, due to the 'find' and 'cellfun', and no longer allows more input arguments than defaults (unless it is possible to guarantee that they are not empty). All in all, a very neat way of setting function default values using current MATLAB syntax.
Henry M. Le replied on : 35 of 37
I tried to create the unitstep function. function [y] =unitstep(time, ts) % y = 0 when time ts y = [zeros(1,length(time) length(ts))]; end when I tried to run the function, I did not see anything from the plot time = [-5:1:5]; z3 = unitstep(time,2); plot(z3);
Loren replied on : 36 of 37
Henry- Your function is all zeros except the last point (which I bet you can't see on the right edge, I'm guessing) so you are seeing what you asked MATLAB to plot. Look at the output values to unitstep to see that they are what you want. -Loren
George Mylnikov replied on : 37 of 37
This function parses the variable input list transparently so that one can immediately see the list and the names of all optional inputs. function varargout = parseVarargin(x, maxVarArgIn) % parseVarargin % This utility function parses the variable length input argument list % INPUTS: % x - varargin from the calling function % maxVarArgIn - maximal number of the input arguments for the calling % function. % OUTPUT: % An array of size 1 x maxVarArgIn % USAGE % (based on an example by Loren Shure % https://blogs.mathworks.com/loren/2009/05/05/nice-way-to-set-function-defaults/) % function y = somefun2Alt(a,b,varargin) % % Some function that requires 2 inputs and has a maximum of 3 optional inputs % % Use parseVarargin to parse the inputs and place optional args in % % memorable variable names: % [tol, mynum, func] = parseVarargin(x, 3); % % If only first two optional arguments were supplied by the user, then % % the variable func will have value [] % % Now set up some default values: % if isempty(tol), tol = eps % if isempty(mynum), tol = 17 % if isempty(func), tol = @magic % Author: George Mylnikov % Date: 28-Dec-2011 optArgIn = size(x,2); if optArgIn > maxVarArgIn error('parseVarargin:TooManyInputs', ... 'takes at most %d optional inputs', maxVarArgIn); end if optArgIn < maxVarArgIn c = cell(1, maxVarArgIn - optArgIn); out = [x, c]; end for k = 1:maxVarArgIn varargout{k} = out{k}; end end