How to use Matlab Coder to create object whose property is a container of unknown value classes
6 views (last 30 days)
Show older comments
I am trying to convert a portion of a large program to a MEX file via MATLAB Coder. This code involves a user-defined value class, "World". The "World" class has a property, "objects" which is a cell array of other user-defined value classes ("Cube", "Sphere", "Cylinder", etc), each of which is a sub-class of the "Shape" superclass. The program should allow users to include an arbitrary number of "Shape" objects (upto an upper bound, say 10), in an arbitrary order in their "World". To this end, I created the following function which works fine in MATLAB:
function wrld = create_world(objIndxList)%#codegen
% First create instance of World class. World is a user-defined value class with "objects" property.
% The "objects" property is pre-allocated as a 1x10 cell array for compatability with codegen and hetereogeneous cell arrays.
% Each element of "objects" is initally a dummy sub-class of the user-defined "Shape" superclass
% The purpose of the create_world function is to replace some or all of the dummy sub-class objects with actual sub-class objects (e.g.,
% Cube, Sphere, Cylinder, etc)
wrld = World();
numObj = length(objIndxList); % This is the number of dummy Shape objects to replace
wrld.objCodes(1:numObj) = objIndxList; % Dummy objects have 0 as their code, whereas real objects are > 0
L = coder.const(length(wrld.objects)); % codegen requires const bounds on for loop
for i=1:L
if objIndxList(i) == 1
wrld.objects{i} = Cube();
elseif objIndxList(i) == 2
wrld.objects{i} = Sphere();
elseif objIndxList(i) == 3
wrld.objects{i} = Cylinder();
else
error('Incorrect object code')
end
if i==numObj % break from for loop once non-null objects are exhausted
break
end
end
end
For example, the output called from MATLAB with [1,2,3] as the input looks like the following:
wrld = create_world([1 2 3])
wrld =
World with properties:
objects: {1×10 cell}
objCodes: [1 2 3 0 0 0 0 0 0 0]
where objects{1:3} are 1x1 Cube, 1x1 Sphere, and 1x1 Cylinder, respectively, and objects{4:10} are 1x1 ShapeDummy.
However, using MATLAB Coder, I continuously get "Type name mismatch: ShapeDummy~=Cube", "Type name mismatch: ShapeDummy~=Sphere", "Type name mismatch: ShapeDummy~=Cylinder" errors. I understand that with C++, the type is static. So when I pre-allocate each cell of the "objects" cell array to ShapeDummy, a type mismatch is registered. I am wondering if there is a workaround of any sort for this type of problem, as it seems fairly generic.
Reading the following link: https://www.mathworks.com/help/simulink/ug/homogeneous-vs-heterogeneous-cell-arrays.html, it appears I am obeying all rules to create a heterogeneous cell array, namely fixed size, indexing into it with a constant upper bound.
Does anyone know if I am missing something or there is a workaround here?
2 Comments
Alexander Bottema
on 10 Sep 2020
There are two issues here:
1) MATLAB Coder does not support changing types (dynamically.) Once you've assigned one thing (ShapeDummy) you cannot switch to another (Cube, Sphere Cylinder)
2) MATLAB Coder does not support object dynamic dispatching. In C++ you would likely use virtual methods and class inheritance to achieve the desired implementation. However, MATLAB Coder doesn't support this.
So hetereogenous cell arrays means that the types can vary at each slot, but once you've assigned it one type it cannot change. Heterogenous cell arrays will in C code be implemented with a struct where each field of the structure is representing each cell array slot respectively. For this reason, hetereogeneous cell arrays has the limitation that referring to a particular cell-array slot, it needs to be constant at compile-time. For-loops referring to a cell array slot 'i' are unrolled, to ensure that all cell-array references are constants (otherwise we cannot map it to a particular structure field.)
Homogeneous cell arrays does not have this limitation (i.e. indexing into them can be determined at run-time) but then the underlying base type must be the same.
The only workaround I can think of is not to store the objects directly (in your World class), but just use pure numbers of some sort (use homogeneous cell arrays, structure arrays, etc.) Then you can create some methods that will recreate the proper object from those numbers. For example,
world.isSphere(id) -> true|false
world.getSphere(id) -> Sphere (this would be an actual class)
Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!