Skip to content

Argument handling

Peter Corke edited this page Jun 16, 2020 · 2 revisions

Argument handling in MATLAB

MathWorks have evolved the way they handle optional parameters. It used to be additional parameters to the function and handled by varargin and nargin. It was often difficult to remember the order and meaning of additional parameters.

They later standardised on keyword-value pairs, where the keyword is a string. For example:

plot(x, y, 'Color', 'red', 'LineWidth', 2)

where the keyword is a character array (single quotes) or a string (double quotes).

Code support in MATLAB was originally quite sketchy but from 2007 there is inputParser which is a bit like Python's argparse for command line arguments.

Since their support was sketchy I wrote tb_optparse to do the job, but it's not strict about keyword-value pairs. In addition it lets you handle keyword-only options like:

R = rotx(30, 'deg')

that can have a negative form like:

R = rotx(30, 'nodeg')

or enum like form

R = rpy2r(angles, 'xyz')
R = rpy2r(angles, 'zyx')

Full details are given at the end of this page. The arguments and their defaults are expressed quite concisely using a MATLAB struct.

Python

Python allows both positional or keyword based arguments, and distinguishes between the two. Consider the case of Link. Using just positional arguments it would be

Link(0, 1, 2, 3)

which makes it difficult for the reader to know what's going on. It also makes it difficult to handle defaults.

Using keyword-value arguments, in MATLAB or Python, would be:

Link('d', 0, 'theta', 1, 'alpha', 2, 'a', 3)

which is easy to read, but a bit cumbersome to write. For MATLAB tb_optparse makes it easy to handle the arguments.

function Link(varargin)
    opt.d = 0
    opt.theta = 0
    opt.alpha = 0
    opt.a = 0
    opt = tb_optparse(opt, varargin)

and for Python we could convert the argument into a list of keyword-value tuples by:

def Link(*pos):
    kwval = [(pos[i], pos[i+1]) for i in range(0, len(pos), 2)]

and then process the tuples.

The Pythonic way would be to use named arguments

Link(d=0, theta=1, alpha=2, a=3)

We could handle both keyword-value and named arguments with a signature like

def Link(*pos, d=0, theta=0, a=0, alpha=0):

but it would require a lot of logic to work out which types of arguments are being passed, to handle malformed or mixed parameter specifications etc.

We need to make a decision on RTB-M compatibility (a good thing) with ugly code and non-Pythonic expression.

We should decide this relatively early. Do we:

  • cut the cord
  • keep the cord for a few select functions, but then what's the algorithm to choose those?
  • keep compatibility for all functions
  • in the spirit of 2to3 do we make the mother of all awk scripts to do this for users

Partial documentation for tb_optparse

% The software pattern is:
%
%         function myFunction(a, b, c, varargin)
%            opt.foo = false;
%            opt.bar = true;
%            opt.blah = [];
%            opt.stuff = {};
%            opt.choose = {'this', 'that', 'other'};
%            opt.select = {'#no', '#yes'};
%            opt.old = '@foo';
%            opt = tb_optparse(opt, varargin);
%
% Optional arguments to the function behave as follows:
%   'foo'              sets opt.foo := true
%   'nobar'            sets opt.foo := false
%   'blah', 3          sets opt.blah := 3
%   'blah',{x,y}       sets opt.blah := {x,y}
%   'that'             sets opt.choose := 'that'
%   'yes'              sets opt.select := 2 (the second element)
%   'stuff', 5         sets opt.stuff to {5}
%   'stuff', {'k',3}   sets opt.stuff to {'k',3}
%   'old'              synonym, is the same as the option foo
Clone this wiki locally