which way to call function is better?

I have more than hundred of input parameters in myfunc and I am using the following way to call the function after grouping the parameters in the cell array C.
C = {a,b,c};
d = myfunc(C{:});
function d = myfunc(a,b,c)
d = a * b + c;
end
I am wondering wether the following way is better or not
C = {a,b,c};
d = myfunc(C);
function d = myfunc(C)
[a,b,c] = C{:};
d = a * b + c;
end

2 Comments

Stephen23
Stephen23 on 5 Sep 2019
Edited: Stephen23 on 5 Sep 2019
"which way to call function is better?"
Neither: using positional input arguments with "more than hundred" parameters is madness.
Just use a scalar structure. Within the function access the fields of the structure directly (i.e. do NOT try to allocate the field values to individual variables). A scalar structure of parameters = more robust, easier to work with, easier to debug, fewer chances of mistakes.
G A
G A on 5 Sep 2019
Edited: G A on 5 Sep 2019
Thanks Stephen!
I have started to do changes in my code following your advise.

Sign in to comment.

 Accepted Answer

John D'Errico
John D'Errico on 5 Sep 2019
Edited: John D'Errico on 5 Sep 2019
Neither way is "better". Both feel just a little clumsy, since I'm not sure why you feel the need to package the variables together in a cell array at all.
The first form seems a bit cleaner in my eye, perhaps closer to traditional MATLAB.
The latter form seems like it does not require the function to have a fixed number of input arguments. So arguably, there could be some elegance in the second one too. But then, the very first thing you needed to do was to unpack the arguments [a,b,c] into a fixed set of variables. So any elegance that seemed to be there is imediately gone.
Neither method will be more efficient. In both cases, you create a cell array, then unpack the cell array into a comma separated list via C{:}. So you're doing exactly the same thing, except that in one case, the comma separated list happens outside the function call, and in the other, the list creation happens inside the function.
Again, as I said, both forms seem a bit of a clumsy way to code. If you absolutely feel the need to use one of them, pick the one that makes you more happy.
Edit: I see that you have a hundred or so various parameters in your function, so you don't want to have a function call with a hundred input arguments. This seems to make some sense, that you don't want an extensive argument list.
In that case, a common approach is to pack the elements into a structure. Now you can access them directly as S.a, S.b, S.c, never needing to unpack them at all. But that makes more typing when you write your function, since you would need to attach the characters S. in front of each variable.
Of course, you could use tools like struct2cell to automatically unpack the struct. But that begs the question of why you wanted to created the struct as a package for your variables at all.
So, since you have a huge number of arguments, perhaps the second way seems simplest in the end. It allows you to not need to write a function header with that huge list of arguments.

11 Comments

G A
G A on 5 Sep 2019
Edited: G A on 5 Sep 2019
Thanks, John!
"So you're doing exactly the same thing, except that in one case, the comma separated list happens outside the function call, and in the other, the list creation happens inside the function."
That was my question - is it exactly the same thing or not.
I agree that my program is clumsy: it is a result of adding to my GUI one feature after another until it does 'everything'. May be I have to read (collect) the parameters from GUI uicontrols as fields of a structure or structures, not as variables. Then I will not need to fold and subsecuently unfold them.
Using a struct is a great way to collect lots of variables, especially gui related ones. That is a very strong preference of mine. It keeps things very nice and tidy, with everything you need in one place.
For example, for a gui application, you might have user data, user prefs, gui handles for callbacks, etc. So use a multi-level struct, instead of one struct, with 100 diifferent top level fields. That is, you might have
S.Data.stuff
S.UserPrefs.stuff
S.Handles.MainGui.stuff
S.Handles.SecondaryGui.stuff
Now, when you need to access something, everthing is neatly stored in one place. Easy to find. Your code becomes easy to read, easy to write, easy to debug when that becomes necessary. I never need to debug my own code, of course, but I have heard that other people sometimes need to do that. ;-)
Another nice feature is this makes your code easily extensible. You just add more fields as needed in the proper place in your struct. I would strongly recommend this as a good general programming style for this class of problem, even if not for this code, for the next one you write.
The structure not only facilitate code maintenance and readability, it's also more efficient. So +1 for using STRUCT
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
g = 7;
h = 8;
i = 9;
j = 10;
C = {a,b,c,d,e,f,g,h,i,j};
s = struct('a',a,...
'b',b,...
'c',c,...
'd',d,...
'e',e,...
'f',f,...
'g',g,...
'h',h,...
'i',i,...
'j',j...
);
timeit(@() myfuncl(C{:})) % 2.3619e-06
timeit(@() myfuncc(C)) % 5.0255e-06
timeit(@() myfuncs1(s)) % 2.3011e-06
timeit(@() myfuncs2(s)) % 1.9034e-06
function z = myfuncl(a,b,c,d,e,f,g,h,i,j)
z = a+b+c+d+e+f+g+h+i+j;
end
function z = myfuncc(C)
[a,b,c,d,e,f,g,h,i,j] = C{:};
z = a+b+c+d+e+f+g+h+i+j;
end
function z = myfuncs1(s)
a = s.a;
b = s.b;
c = s.c;
d = s.d;
e = s.e;
f = s.f;
g = s.g;
h = s.h;
i = s.i;
j = s.j;
z = a+b+c+d+e+f+g+h+i+j;
end
function z = myfuncs2(s)
z = s.a+s.b+s.c+s.d+s.e+s.f+s.g+s.h+s.i+s.j;
end
If I have struct S with handreds of fields and I want to pass only few fields to some function, then how big is differense between two following calls concerning memory and performance?
d = func1(S.a,S.b,S.c);
d = func2(S);
function d = func1(a,b,c)
d = a * b + c;
end
function d = func2(S)
d = S.a * S.b + S.c
end
Forget func1 and adopt func2.
The advantage (as people keep telling you) is that you might able to change later what to use in S and still calling exactly the same manner.
function d = func2(S)
d = S.a * S.b + S.c + S.correction
end
There is practically no speed penaly of passing a big structure (with 100 fields) and use small part of it.
But you must think about if it's make sense to pass a nested structures and range your data hierachically rather than fold them in series of 100 fields in a single structure.
You can test this yourself with tic and toc, or convert each option to a wrapper function and use timeit.
John, Bruno, Rik, thanks!
It was very useful discussion!
There is NO time penalty passing a struct with one field vs passing a struct with 100's of fields to a function. In both cases, exactly the same thing happens ... a shared data copy of the struct is created and passed into the function (as a general rule this happens with all agruments ... not just the structs). So, in addition to the overhead of creating a new variable to pass (which happens in both cases), only a single pointer (an 8-byte quantity on 64-bit machines) to the data area of the struct is all that get's copied in both cases. I.e., the exact same effort is involved. In particular, the field variables are not copied, and in fact the pointers to the field variables aren't even copied. The penalty of deep copies would only be paid if you modified any of the fields in the function.
Bottom line: It takes the exact same amount of effort to pass a single struct with one field as it does to pass a huge struct array with 100's of fields.
What about the difference (in penalties) in using the relatively big structure S in the following two ways?
[S.a,S.b] = func1(S);
S = func2(S);
function [a,b] = func1(S)
a = S.c + S.d;
b = S.c - S.d;
end
function S = func2(S)
S.a = S.c + S.d;
S.b = S.c - S.d;
end
There shouldn't be any significant difference between func1 and func2. MATLAB duplicates the structure field pointers when a/b change (but not the fields that have not been modified). In one case (func2) it's carried out inside the function, in other case (func1) outside juste after function returns. You shouldn't worry at this level and let MATLAB does the work, it's usually efficient.

Sign in to comment.

More Answers (1)

I have more than hundred of input parameters in myfunc and I am using the following way to call the function after grouping the parameters in the cell array C.
Are the parameters a,b,c, all scalars? If so, you should be carrying them around and passing them to functions as a vector
v=[a,b,c,...]
not as a cell array or struct.

Categories

Products

Asked:

G A
on 5 Sep 2019

Commented:

G A
on 7 Sep 2019

Community Treasure Hunt

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

Start Hunting!