Given a function like:
function foo(myParam)
if nargin<1
myParam = \'default value\';
end % if
end % function
I\'ve seen people use so
I strongly prefer exist
over the nargin
option for two reasons.
1.
After reading a lot of code from people who were never taught to look back at their own code, I have only felt stronger for this, as exist
makes the code readable.
For example, I encountered once a function like this. For your convenience I gave the variables sensible names:
[model, accuracy] = epicModelingFunction (dataMatrix, responseVector, indicatorForCategoricalVariables, optionsForInternalFunctions, typeOfDistanceCalculation, notationForMissingValues, isClassificationAndNotRegression, scalingMethod, shouldPlotAllIntermediateStuff)
% EPICMODELINGFUNCTION is actually a horrible function to read and not epic at all
% ...
This was then followed by if nargin < n
for every variable other than the first two. The only reason I could follow what the nargin(n)
should be without counting the header input, is that the if nargin < n
was always followed by (only sometimes a few lines of code and) the declaration of the missing input with the default value. For bigger chucks of code in the if nargin < n
, I would definitely lose track.
2. exist
doesn't really check the complete workspace if called from a function. Sure, comparing two numbers is less expensive as comparing a few strings, but if used at the beginning of a function to fill in default values for the not given parameters, it is fine. Consider the following function:
function testExist(C)
if exist('B', 'var')
disp('''exist'' in a function checks the workspace.')
elseif exist('C', 'var')
disp('''exist'' in a function ignores the variables in the workspace, but checks the function space.')
else
disp('''exist'' is broken or no parameter was given.')
end
end
And then executing the following:
A = magic(3);
B = magic(4);
testExist(A)
results in this output:
'exist' in a function ignores the variables in the workspace, but checks the function space.
Both should work. But...
Exist tends to be slow, since it must look through your workspace for the variable in question. When you write error checks like this, you don't want them to suck up CPU cycles. The test against nargin is a simple test against a single numeric value.
I'd also generally suggest a more extensive test. Something like
if (nargin<1) || isempty(myparam)
myparam = defaultvalue;
elseif
...
end
Inside the elseif branch, I'll put a set of additional tests to see if the parameter has the expected size, shape, class of variable, etc. If those tests fail, I'll return a friendly error message that explains what was wrong.
For those using MATLAB R2007b or later,
here is a better answer: InputParser
It saves the trouble of having to synchronize any addition, removal, renaming and reordering of arguments.
(How much you save would depend on your coding style, but there is not a more neat way than InputParser.)
I have not tested it for speed, but if you function takes more than 1000 milliseconds to run, there's no reason to be concerned by the speed of InputParser.
Example:
function AbCdEfGhIj(ffff, ggggg, varargin)
opts = inputParser;
opts.addRequired('ffff', @(p)(ischar(p) && size(p,1)==1 || iscell(p)));
opts.addRequired('ggggg', @(p)(iscell(p) && all(cellfun(@ischar,p))));
opts.addOptional('Recursive', false, @islogical);
opts.addOptional('IncludeFullPath', logical([]), @islogical);
opts.parse(ffff, ggggg, varargin{:});
opts = opts.Results;
if isempty(opts.IncludeFullPath),
opts.IncludeFullPath = iscell(opts.fffff) || opts.Recursive;
end
I'd go with the NARGIN option, for the reasons listed by SCFrench. One additional benefit: I often find myself using it in conjunction with a SWITCH statement when I have more than 2 input arguments:
function outArgs = my_fcn(inArg1,inArg2,inArg3)
switch nargin,
case 0, % No input case
error('Not enough inputs!');
case 1, % Set last 2 inputs to default
inArg2 = 'yes';
inArg3 = 'on';
case 2, % Set last input to default
inArg3 = 'on';
end
...
% Checking of variable types and values would go here!
...
end
I always validate arguments using nargchk
, and then go with the nargin
tests as you had them. As others pointed out, they're cheaper, and I think clearer.
In functions that I expect to be re-used heavily, I always put lots of checks up front, and then structure the code to call the real implementation later.
I also tend to structure optional arguments (when not using varargin
) like this:
function x = myfcn( arg1, opt_arg2 )
if nargin < 2
arg2 = 'default';
else
arg2 = opt_arg2;
end
as I think this makes it more obvious when editing the file which arguments are expected to be optional.
I would go with nargin for two reasons:
If you change the order of parameters to your function, fixing up the input checking code is going to be the least of your problems; you're going to have to go update all the call sites to your function as well.
nargin is far cheaper. exist, even if scoped to just check for variables, has to scan the whole workspace doing a bunch of string comparisons along the way. the nargin method consists of just a scalar less than operation.