Clear Filters
Clear Filters

Proper way of define a function with struct: readability vs reusability

4 views (last 30 days)
Hi all,
Imagine there is a function with many inputs and outputs, according to my knowledge there are two ways to design this function:
Method_1. explicitly write all inputs and outputs:
function [otpt_b1, otpt_b2, ......, otpt_bn] = test(inpt_a1, inpt_a2, ......, inpt_an)
some operations
Method_2. use struct as inputs and outputs, i.e.
inpt = struct('a1', 'a2',......, 'an');
otpt = struct('b1', 'b2', ......, 'bn');
function [otpt] = test(inpt)
some operations
Method_1 is reusable for different inputs, as long as one knows the corresponding location of inputs. For example, this will work:
[otpt_y1, otpt_y2, ......, otpt_yn] = test(inpt_x1, inpt_x2, ......, inpt_xn)
Method_2 is much more readable, especially when number of outputs and inputs are large. However, one cannot change the content of struct input (the function can only recognise inpt.a1, inpt.a2, etc.), for example, this won't work:
inpt = struct('x1', 'x2', ......, 'xn');
otpt = struct('y1', 'y2', ......, 'yn');
[otpt] = test(inpt)
My question is: what if I want the function to be reusable and readable, i.e. I'd like to use struct as input and output, is there a way to combine advantages of both method_1 and method_2?
Thank you!

Accepted Answer

Guillaume
Guillaume on 9 Mar 2017
I'm not sure if this is what Walter was hinting at, but another option is, instead of a plain function use a function object, where (most) of the arguments and the function is part of the same class. So unlike, the OOP approach you tried, no object is passed to the function. Example:
classdef myplot < matlab.mixin.Copyable
properties
linecolour = 'b'; %default values
linewidth = 1;
linestyle = '--';
end
methods
function doplot(this, x, y)
plot(x, y, 'LineColor', this.linecolour, 'LineStyle', this.linestyle, 'LineWidth', this.linewidth);
end
function set.linecolour(this, colour)
%validation for linecolour
this.linecolour = colour;
end
function set.linewidth(this, width);
validateattributes(width, {'numeric'}, {'scalar', 'positive'});
this.linewidth = width;
end
function set.linestyle(this, style)
%validation for linestyle
this.linestyle = style;
end
end
end
The advantage of this method:
  • Unlike the name/value method you don't have to remember the names/spelling of the optional arguments. Autocompletion shows you all the options
  • Easy reuse of the optional arguments. You only set them once and can call the function multiple times without having to pass them again. And you can easily change any option between call
p = myplot;
p.linecolour = 'r';
p.linewidth = 2;
p.doplot(1:10, 1:10);
hold on;
p.doplot(2:20:, 20:-1:2); %reuse the same options as the first call
p.linestyle = ':';
p.doplot(1:10, sin(1:10)); %reuse the same options as the first call and 2nd call but the linestyle
  • validation of the optional arguments when they're set, not when the function is executed, so the function execution is much faster (important when it's called in a loop). All that time consuming parsing is already done when you actually call the function.
The downside is that it may be a bit slower than a plain function due to the OOP overhead.

More Answers (1)

Walter Roberson
Walter Roberson on 8 Mar 2017
One possibility you missed was to encapsulate related properties into objects. That has similarities to using (multiple) structures, but leads to opportunity for generalization of the code.
Anyhow: my experience has been that long before argument lists get long enough for "readability" to be a primary factor, that writability becomes a problem. People just aren't good at remembering the proper order for longer sequences of arguments, and it is easy to accidentally drop arguments.
For a long time I resisted learning how to use the MATLAB argument parsing routines, but once I had done half of one, it became clear that using property/value pairs was not hard to program, and is a heck of a lot easier on the user than long argument lists.
In terms of code efficiency: plain parameters is more efficient than a structure. For a structure, each time the fieldnames need to be looked up to find the entry. If you do pass a structure, then for any field of the structure that you use repeatedly, you can gain in efficiency by pulling it out of the structure into a plain variable inside the function.
  3 Comments
Steven Lord
Steven Lord on 9 Mar 2017
Show the exact and full text of the error message as well as the text of the function in which the error occurs.
There is a fourth approach that can be useful if some inputs are required and some optional, and that is to use parameter name/value pairs. For instance, consider sort. Obviously the first input, the array to be sorted, is required. But if you don't have any missing elements in your array, you don't need to worry about where the (non-existent) missing elements are placed in the sorted array. The 'MissingPlacement' parameter is optional.
Xh Du
Xh Du on 9 Mar 2017
I'm not very familiar with name/value pairs, I searched documentation and it gave me setProperties, how can I use name/value pairs in a class?

Sign in to comment.

Categories

Find more on Structures in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!