Time for an Argument
For those Monty Python fans reading this post, check out the Argument Clinic. Recently both Sean and Jiro, twice! posted about the new arguments capability available for input argument checking. I wanted to show you some more about this great feature! I've also discussed argument checking over the years, including this post.
Contents
What Makes a Program Good, or Useful?
Of course, this in the eye of the user frequently, but certainly it helps if you get informative messages when you misuse the program. These messages should help guide you so you can properly use the program without a major headache. To do so generally requires some amount of error checking on the part of the programmer, thinking about what can go wrong, and making sure to give good information if/when it does.
I'm going to show you some code snippets from a routine. The function in question is modeling the dynamics of a virus, given parameters such as the infection rate.
Original error checking, circa 2007
In this first code, I will show you how we did some important error checking about 12 years ago. In 35 lines, we check to see if the user called the function this code is embedded in with 0, 1, or 5 inputs. And we check the types of the inputs. If not all the inputs are supplied by the user, we set the unsupplied variables with default values.
% Allowing for variable number of arguments in switch(nargin) case 5 Tpoints = varargin{1}; % time to evaluate at beta = varargin{2}; % infection rate c = varargin{3}; % clearance rate of virus delta = varargin{4}; % death rate of infected cells p = varargin{5}; % viral production rate of infectious cells case 1 Tpoints = varargin{1}; % time to evaluate at beta = 3.4e-5; % infection rate c = 3.3; % clearance rate of virus delta = 3.4; % death rate of infected cells p = 7.9e-3; % viral production rate of infectious cells case 0 % Use all default values Tpoints = 0:0.1:10; % time to evaluate at beta = 3.4e-5; % infection rate c = 3.3; % clearance rate of virus delta = 3.4; % death rate of infected cells p = 7.9e-3; % viral production rate of infectious cells otherwise error('virusSolve:Input:InvalidNumberOfInputs', ... 'This function expects 0, 1, or 5 inputs.'); end % Error checking - make sure all inputs are valid validateattributes(Tpoints, {'numeric'}, {'vector', 'nonnegative'},mfilename,'Tpoints',1); validateattributes(beta , {'numeric'}, {'scalar', 'real'}); validateattributes(c , {'numeric'}, {'scalar', 'real'}); validateattributes(delta , {'numeric'}, {'scalar', 'real'}); validateattributes(p , {'numeric'}, {'scalar', 'real'});
You can see heavy use of validateattributes as well as the use of nargin, and switch, case, otherwise.
Another solution, similar time frame
There was another solution availabe in about the same time frame using a function called inputParser. Here's what that error checking code looks like.
% Create input parser ps = inputParser(); % Define optional arguments with default values and error checking ps.addOptional('Tpoints', 0:0.1:10, ... @(x) validateattributes(x, {'numeric'}, {'vector', 'nonnegative'})); ps.addOptional('beta', 3.4e-5, ... @(x) validateattributes(x, {'numeric'}, {'scalar', 'real'})); ps.addOptional('c', 3.3, ... @(x) validateattributes(x, {'numeric'}, {'scalar', 'real'})); ps.addOptional('delta', 3.4, ... @(x) validateattributes(x, {'numeric'}, {'scalar', 'real'})); ps.addOptional('p', 7.9e-3, ... @(x) validateattributes(x, {'numeric'}, {'scalar', 'real'})); % Parse parse(ps, varargin{:}); % Extract parameters Tpoints = ps.Results.Tpoints; beta = ps.Results.beta; c = ps.Results.c; delta = ps.Results.delta; p = ps.Results.p;
A bit better if you count lines, we're down to 25, from 35. In this case, you see that the limitation of number of input arguments is relaxed. It can go from 0 to 5 now.
And the modern way, circa 2019
In MATLAB release 2019b, we introduced a new way to perform input argument validation, using the arguments block at the beginning of the function code. Here's how to do what we've previously accomplished in 35, then 25 lines of code.
arguments % R2019b or newer Tpoints(1, :) double {mustBeNumeric, mustBeNonnegative} = 0:0.1:10 beta(1, 1) double {mustBeReal} = 3.4e-5 c(1, 1) double {mustBeReal} = 3.3 delta(1, 1) double {mustBeReal} = 3.4 p(1, 1) double {mustBeReal} = 7.9e-3 end
In 7 lines of code, you can see that we specify the conditions we want for each input, and supply a default value if the input is missing.
This is just a simple example. There is a lot more fodder you can bring to arguments. Check out the documentation to see the possibilities.
Do you have arguments?
How do you resolve your arguments? Let me know here.
- Category:
- Error checking,
- New Feature