Updating Structure Input for Functions

3 views (last 30 days)
Hello,
Let's say I have a structure for fruit:
fruit.appleMass = 0.15; %kg
fruit.appleHeight = 4; %m
Let's say I also have another structure for other variables:
otherParams.gravity = 9.81; %m/s^2
otherParams.newtonHeight = 1.68; %m
I have a simple function to calculate the force of a falling fruit and another simple function to calculate the maximum velocity of a falling fruit based on the apocryphal Isaac Newton tale:
ouch = fruitForce(fruit, otherParams);
yikes = fruitVelocity(fruit, otherParams);
function [ouch] = fruitForce(fruit, otherParams)
ouch = fruit.appleMass*otherParams.gravity;
end
function [yikes] = fruitVelocity(fruit, otherParams)
deltaHeight = fruit.appleHeight - otherParams.newtonHeight;
yikes = sqrt(2*deltaHeight*otherParams.gravity);
end
However, if later I discover I need to add another fruit to my structure, like a coconut, and need to perform the same calculations (poor Newton), I need to update the code.
Creating fields for coconuts is straightforward. Obviously, I could rewrite my functions to replace instances of apples with coconuts or add lines to calculate both apples and coconuts simultaneously. However, updating my functions each time I have a new fruit seems very ineffcient and seems highly prone to issues if I later have several function files calling fields from my fruit structure.
I think there is an easy way to update the code for an arbitrary number of fruits but not sure what that entails. What would be the best way to update and future proof the code? Should I have written the initial code differently before knowing there would be other fruits besides apples?
I have searched for similar questions and answers but didn't see anything similar (not sure what keyword I am missing). Insight would be much appreciated.
  3 Comments
Jekazu
Jekazu on 8 Jan 2024
Hello Stephen,
Well, I admit I feel rather silly for missing something as simple as nonscalar structure arrays. I appreciate that you addressed many of the points in my inquiry.
Stephen23
Stephen23 on 8 Jan 2024
Edited: Stephen23 on 9 Jan 2024
Don't feel silly. I am just trying to show that a change of perspective helps: MATLAB is based on arrays, so you should always try to solve tasks first using arrays... and only if that does not work (unlikely) try something else.
This applies to all programming languages of course: if language X is based on Y... then it makes sense to use Y when writing code in X (at least as a starting point).
"I appreciate that you addressed many of the points in my inquiry."
Let me know what I missed, I am happy to clarify or provide examples.

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 8 Jan 2024
Edited: Stephen23 on 9 Jan 2024
Do not use nested structures.
Definitely do NOT use lots of variables each named after a fruit! Ugh, no.
Use a structure array:
S(1).name = 'apple'
S(1).mass = 0.15; %kg
S(1).height = 4; %m
S(2).name = 'banana'
S(2).mass = 0.1; %kg
S(2).height = 2; %m
Do not make your data any more complex than that.
Do not force meta-data (e.g. names of fruit) into fieldnames or variable names (unless you want to force yourself into writing slow, complex, inefficient, buggy code that is hard to debug). Meta-data is data: data belongs in your variables, not in the variable/field names. Data in variables makes it much easier to write expandable, generalizable, efficient code. See also Steven Lord's comment here: https://www.mathworks.com/matlabcentral/answers/2067801-updating-structure-input-for-functions#comment_3022366
Understand that meta-data is data. Then you would avoid the situation that you have gotten yourself into.
  5 Comments
Stephen23
Stephen23 on 9 Jan 2024
Edited: Stephen23 on 9 Jan 2024
"The intent of the function name question was to ask whether or not function names should be as generic as possible or as specific as desired (including metadata like "fruit" in the name). I think for the falling fruit problem, a very generic function name could be "fallingObjectForce" compared to "fruitForce"."
Ah, I see. That is actually a good question. Personally, I would keep functions (and their names) as general as is reasonable**: it often happens that once you do that, other ways to use your functions or approaches to processing your data will appear.
But for a start just focus on robust data design and efficient code.
** You will note that this just shifts the question to "what is reasonable?" Like all other types of engineering, writing code is ultimately a matter of compromise between many many many factors (e.g. correctness, readability, understandability, debuggability, complexity, expandability, generalizability, runtime, maintenance time, etc.) How to balance those priorities depends on you, your projects, your experience, your goals, etc.
If my answer helped you to resolve your original question then please remember to click the accept button!
Jekazu
Jekazu on 9 Jan 2024
Hello Stephen,
I accepted your answer. Thanks for your patience and all of the assistance.

Sign in to comment.

More Answers (2)

Matt J
Matt J on 8 Jan 2024
Edited: Matt J on 8 Jan 2024
If you had as follows, it would work for any fruit, wouldn't it?
fruit.Mass = 0.15; %kg
fruit.Height = 4; %m
  6 Comments
Matt J
Matt J on 8 Jan 2024
If the name of the fruit is meta-data...
Stephen23
Stephen23 on 8 Jan 2024
"If the name of the fruit is meta-data..."
It is.

Sign in to comment.


Walter Roberson
Walter Roberson on 8 Jan 2024
Moved: Walter Roberson on 8 Jan 2024
What if you did something like
fruit.apple.Mass = 0.15; %kg
fruit.apple.Height = 4; %m
fruit.coconut.Mass = 0.89; %kg
fruit.coconut.Height = 4; %m
then you could use dynamic field name references:
fn = fieldnames(fruit);
for fi = 1 : length(fn)
thisfruit = fn{fi};
deltaHeight = fruit.(thisfruit).Height - otherParams.newtonHeight;
yikes.(thisfruit) = sqrt(2*deltaHeight*otherParams.gravity);
end
and the output would be a struct array with one field for each fruit.
  1 Comment
Jekazu
Jekazu on 8 Jan 2024
Hello Walter,
That gives the desired information into a desired format for me. Nested structures seems intuitive, but I hadn't thought about using a cell in a "for" loop before. I really appreciate the response.

Sign in to comment.

Products


Release

R2023b

Community Treasure Hunt

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

Start Hunting!