How do I add a new element to an object array using pass by reference?

Hello,
I am trying to use pass by reference using handle objects.
The scenario I have right now is I have an array of handle objects defined by:
classdef unit < handle
and I'd like to pass an array of such an object to a function which in turn sets a callback to a button that once pressed, should add a new element to that array. I have managed to pass the array through to the callback function. When I change the value of the properties of any of the original elements, the original array gets updated, as expected. However, when I add an element, the new element is lost when the callback function completes, as expected I suppose.
But since I cannot return anything from a callback, what method can I use to add this element and have it update the original object? A couple potential solutions I've thought of:
1. Do I need to pre-augment the array? But I do not know if I need to augment the array until the callback executes.
2. Do I have to create another handle class that is used simply to hold this "unit" object array in a pass by reference scenario? Seems awfully clunky to me.
Thanks in advance!

8 Comments

I have just tried number 2 and it works, it is pretty clunky and I feel like there has to be a better way though.
"[...] when I add an element" How do you add a new object to the array?
I don't think this is an issue of your class being a handle. The object array will hold references to instances, but the array itself wouldn't be a handle, right?
It sounds like you just need a way to pass your object array variable around in your app, such as by making it a property of your app class. If you're using an older style of making apps, look into getappdata/setappdata.
If the original array is 1x3, Im adding the new object to the arry by doing:
unitArray(4) = unit(x,y,z);
I also tried (but it should be equivalent):
temp = unit(x,y,z);
unitArray(4).X = temp.X;
unitArray(4).Y = temp.Y;
unitArray(4).Z = temp.Z;
@J. Alex Lee
Yea thats essentially what I want to do, but I'd rather not pass the entire app class around different functions if possible, since I'd have to edit a lot of generic functions to work specifically with the app
are you sure your design should be passing around the entire app around different functions, or should your app class define the relevant methods that can operate on different properties of the app? do you need access to unitArray from outside the app?
Yes, I do not want to be passing around the entire app. unitArray can be used in a lot of functions that are already in a library outside the app.
The solution by per isakson addresses allocation of an object array, plus some mechanisms to track the size. Is this the question you wanted answered? Or are you asking about growing the object array within an app and then later accessing that array from outside the app?

Sign in to comment.

 Accepted Answer

The documentation on Initialize Arrays of Handle Objects says "[...] Creates unique handles for each element in the array." I assume that explains the behaviour you see.
Another potential solution: Preallocate a large enough array. It doesn't require that much memory. And implement a mechamism to keeps track of the "current size" of the arryay. MWE:
>> object_array(1,12) = MyClass(-1);
>> add_MyClass_object( object_array )
>> add_MyClass_object( object_array )
>> add_MyClass_object( object_array )
>> [object_array.ID]
ans =
1 2 3 -1 -1 -1 -1 -1 -1 -1 -1 -1
>>
where
classdef MyClass < handle
properties
ID
end
methods
function this = MyClass( id )
if nargin == 0
this.ID = -1;
else
this.ID = id;
end
end
end
end
and
function add_MyClass_object( array )
nxt = find( [array.ID] == -1, 1, 'first' );
array(1,nxt).ID = nxt; %#ok<*NASGU>
end
Your "awfully clunky" approach is that something like this?
>> ac = ArrayContainer;
>> ac.add_object
>> ac.add_object
>> ac.add_object
>> [ac.object_array.ID]
ans =
1 2 3
where
classdef ArrayContainer < handle
properties
object_array (1,:) MyClass = MyClass.empty
end
methods
function add_object( this )
len = numel(this.object_array);
this.object_array(1,end+1) = MyClass(len+1);
end
end
end
Comment: When using approaches like these in real applications one will certainly encounter problems, which one didn't anticipate up front. Experiments are needed, e.g.
>> ac.object_array(2).ID = 200;
>> [ac.object_array.ID]
ans =
-1 200
>>
:-( What *** happened? )-:
Guess what this returns
%%
object_array(1,12) = MyClass(-1);
add_MyClass_object( object_array )
add_MyClass_object( object_array )
add_MyClass_object( object_array )
[object_array.ID] %#ok<*NOPTS>
%%
object_array(1,2).ID = 200;
[object_array.ID] %#ok<*NOPTS>
Conclusion: Don't try to outsmart Matlab!
/R2018b

4 Comments

the clunky one is basically like that yes. it is definitely not ideal and would require me to edit the library also
Wouldn't "Preallocate a large enough array." work. That's a documented solution, which mean that you don't need for prepare for nasty surprises.
i would like to avoid that if possible because this array has to be saveable to its exact size and it would require some post processing and pre-processing as the data was loaded back into the app. Is there really no way to be able to append an element by reference?
Not as far as I know. Depending on your license (i.e. other than student) you might ask the technical support.

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2020a

Community Treasure Hunt

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

Start Hunting!