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

functionmethodsstruct

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!

Best Answer

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.