dealing with variable options (varargin) in matlab

Summary

There are various ways to handle variable input arguments (varargin) in Matlab. I present the standard getOptions method I developed that is simple, flexible, and allows for more readable code.

Update getOptions now has a repository: https://github.com/bahanonu/getOptions or https://www.mathworks.com/matlabcentral/fileexchange/75464-getoptions.

Matlab doesn't adopt R, python, or various other language's syntax for passing optional arguments, namely, you can't specify the name-value pair in the list of inputs to the function. While this might initially seem to be a weakness, it can allow for cleaner, more flexible code with the right planning.

The main goal is to have a set of inputs that have default states within the function—often magic numbers or other hard-coded constants are placed here so they are easily edited and their impact understood. One way to deal with Matlab's method of passing optional parameters is to just pass an options structure as the sole name-value pair, with fieldnames containing the options used by the function.

download optionsStructExample.m

Matlab M
  1. % get an options structure from varargin, search for fields
  2. options=[];
  3. foo=0;
  4. bar = 'hello world';
  5.  
  6. if ~isempty(varargin)
  7.     options=varargin{1};
  8.     if isfield(options, 'foo')
  9.         foo=options.foo;
  10.     else
  11.         foo=0;
  12.     end
  13.     if isfield(options, 'bar')
  14.         bar=options.bar;
  15.     end
  16. end

However, this is not very flexible and the feature cannot be easily enhanced across all functions in a project. Further, it is not the most readable or consistent code and the same sequence of actions is repeated in the actual source code instead of dynamically/filter grabbing options set in the input. Another method is to then loop over name-value pair inputs.

download vararginForLoop.m

Matlab M
  1. for i = 1:2:length(varargin)
  2.     val = lower(varargin{i});
  3.     switch val
  4.         case 'foo'
  5.             foo = varargin{i+1};
  6.         case 'bar'
  7.             bar = varargin{i+1};
  8.         otherwise
  9.             disp('option not available!');
  10.     end
  11. end

This method isn't necessarily better, but solves the problem in a slightly different manner that in essence keeps the same problems: it still relies on a hard-coded enumeration of all acceptable variable input parameters. As more options are added, this can grow to consume a good chunk of the introductory code in a function and is not super friendly to someone skimming the code.

An alternative method is presented below (see getOptions.m). The idea is to take advantage of the repeated nature of how variable input arguments are dealt with along with dynamic filtering to ensure that the user cannot input invalid parameters. The solution is to always put all available options into a structure, called options, at the beginning of each function. This structure contains fieldnames that a user can input via classic name-value pairs, e.g. foobar('electionYear', 1992), or via a special options name-value pair wherein an options structure is created with fieldnames to be modified (see exampleScript.m below). In either case, a single function then deals with looping over all variable inputs and replaces the default values that match a valid fieldname. This is done dynamically, which means that if additional options are added, no new code is needed to help filter and add the new options name-value pairs to the functions settings.

While this introduces some restrictions on how a function responds to a given input, e.g. you cannot immediately call a new function based on user input before parsing all variable arguments (perhaps for the better), it forces a consistent format to how options are dealt with and allows for added functionality to be implemented across all functions in a project quickly.

For example, the special options name-value input argument was added later and instantly allowed me to reduce super-long code-lines with a ton of name-value pairs to several lines each with a single fieldname and input value, allowing for easier readability and (in the future) more dynamic parameter passing. This would have been much harder to implement across every script in my current project using the two previous methods.

More small code snippets to come in the future, for now, enjoy the example below!

download exampleScript.m

Matlab M
  1. % pass option via a name-value pair
  2. [output] = exampleFxn('foo',1,'bar','Call me Ishmael');
  3.  
  4. % or pass option via options structure
  5. inputOptions.foo = 1;
  6. inputOptions.bar = 'Call me Ishmael';
  7. [output] = exampleFxn('options',inputOptions);
download exampleFxn.m

Matlab M
  1. function [output] = exampleFxn(varargin)
  2.         % example function with outline for necessary components
  3.         % biafra ahanonu
  4.         % updated: 2014.02.17
  5.  
  6.         %========================
  7.         options.foo = 0;
  8.         options.bar = 'hello world';
  9.         % get options
  10.         options = getOptions(options,varargin);
  11.         % display(options)
  12.         % unpack options into current workspace
  13.         % fn=fieldnames(options);
  14.         % for i=1:length(fn)
  15.         %       eval([fn{i} '=options.' fn{i} ';']);
  16.         % end
  17.         %========================
  18.  
  19.         try
  20.                 if options.foobar==1
  21.                         display(options.bar);
  22.                         % do something
  23.                 else
  24.                         % do something else
  25.                 end
  26.         catch err
  27.                 display(repmat('@',1,7))
  28.                 disp(getReport(err,'extended','hyperlinks','on'));
  29.                 display(repmat('@',1,7))
  30.         end
download getOptions.m

Matlab M
  1. function [options] = getOptions(options,inputArgs,varargin)
  2.     % gets default options for a function, replaces with inputArgs inputs if they are present
  3.     % biafra ahanonu
  4.     % 2014.02.17 [22:21:49]
  5.     %
  6.     % inputs
  7.     %   options - structure with options as fieldnames
  8.     %   inputArgs - varargin containing name-value pairs passed from parent function.
  9.  
  10.     % list of valid options to accept, simple way to deal with illegal user input
  11.     validOptions = fieldnames(options);
  12.  
  13.     % loop over each input name-value pair, check whether name is valid and overwrite fieldname in options structure.
  14.     for i = 1:2:length(inputArgs)
  15.         val = inputArgs{i};
  16.         if ischar(val)
  17.             % allow input of an options structure that overwrites existing fieldnames with its own, for increased flexibility
  18.             if strcmp('options',val)
  19.                 inputOptions = inputArgs{i+1};
  20.                 [options] = mirrorRightStruct(inputOptions,options);
  21.             elseif ~isempty(strmatch(val,validOptions))
  22.                 options.(val) = inputArgs{i+1};
  23.             end
  24.         else
  25.             continue;
  26.         end
  27.     end
  28.  
  29. function [pullStruct] = mirrorRightStruct(pushStruct,pullStruct)
  30.     % overwrites fields in pullStruct with those in pushStruct, other pullStruct fields rename intact
  31.     % more generally, copies fields in pushStruct into pullStruct, if there is an overlap in field names, pushStruct overwrites.
  32.     pushNames = fieldnames(pushStruct);
  33.     for name = 1:length(pushNames)
  34.         iName = pushNames{name};
  35.         pullStruct.(iName) = pushStruct.(iName);
  36.     end

-biafra
bahanonu [at] alum.mit.edu

additional articles to journey through:

quicklinks github
12 august 2012 | programming

quicklinks is a new homepage for those looking for efficiency over lavish use of big buttons commonly seen in Firefox, Opera and other brow[...]ser's homepages. As quicklinks is still a little rough around the edges and needs to be updated, I've added it to GitHub to allow me to update it easier.

¿qué es la calle?
24 may 2013 | short story | spanish

Había terminado y salé para mi cocina. Tenía hambre pero este día no había comida dentro de mi despensa. Me fui y caminé hacienda[...] la Tport—una máquina que puede transportar una persona a otro lugar sin energía y tiempo. Cuando entré la máquina, toqué algunos botónes y esperé. Pero nada ocurrió y lo hice las mismas acciones otra vez—y nada ocurrió.

How would the disappearance of streets affect the social fabric? This short story briefly (in castellano!) explores a world in which instantaneous, free transport is possible. Meant mainly to practice my spanish, i plan to follow-up with a more detail story in the future.

bio42: notes
12 may 2013 | teaching

While teaching bio42 (cell biology and animal physiology) I created weekly notes to help students in my section study and focus on the impo[...]rtant materials presented in the class. I built off of the latex boilerplate that I have been improving over time to create weekly notes. This highlights why I love LaTeX so much, especially for larger projects that are heavily linked—it allows easy annotation, indexing, creation of new document styles, and other related processes rapidly and consistently. Plus, separating content and style is always a plus and images stay uncoupled from a propriety source (e.g. Word files).

I really love the resulting notes and student feedback was quite positive. I thought sharing them might be useful for others in the future. The source latex files and raw images can be sent upon request (I'm considering making a Github repository in the future). I'll briefly talk about the document below and certain decisions that were made to get it to its current state.

social chair spring 2012
27 december 2011 | psk

My terms as social chair during Fall 2011 went quite well, but there were several things I was unsatisfied with. This presentation outlines[...] several different areas I would like to see improved.

©2006-2025 | Site created & coded by Biafra Ahanonu | Updated 21 October 2024
biafra ahanonu