- Argument validation for cell arrays: https://www.mathworks.com/matlabcentral/answers/2018441-argument-validation-for-cell-arrays#answer_1305481
- Define Validation Functions: https://in.mathworks.com/help/releases/R2022b/matlab/matlab_prog/argument-validation-functions.html#mw_3e8f7e5b-fbb5-4725-be02-4751c675a92a
- ‘mustBeA’ function: https://www.mathworks.com/help/releases/R2022b/matlab/ref/mustbea.html
Cannot define a cell array of custom classes in function argument validation
1 view (last 30 days)
Show older comments
Daniele Lupo
on 1 Oct 2024
Commented: Steven Lord
on 3 Oct 2024
I've a class like the following one:
classdef Session < handle
%SESSION Summary of this class goes here
% Detailed explanation goes here
properties (Access = private)
configurations (1, :) cell {mustBeA(configurations, "App.Core.Configuration")}
end
methods (Access = public)
function this = Session()
this.configurations = {}
end
end
What I want to do is to declare che configuration property as a unidimensional cell array of a custom class, that can have 0 or more elements.
The problem is that I cannot instantiate it. When I try to do something like:
s = App.Core.Session()
I obtain the following error
Error using implicit default value of property 'configurations' of class 'App.Core.Session'. Value must be one of the following types: 'App.Core.Configuration'.
even if the App.Core.Configuration() class exists and it works (I've already unit tested it).
How can I declare correctly my configurations property?
0 Comments
Accepted Answer
Sandeep Mishra
on 3 Oct 2024
Hi Daniele,
I see that you are trying to implement a cell array of a custom class with function argument validation. You can accomplish this by using either of the following two workarounds:
1. You can define a custom function argument validation by creating a separate validation function, such as the ‘validator’ function in the following example:
function validator(configurations)
for i = 1: numel(configurations)
config = configurations(i);
mustBeA(config{1}, 'Configuration');
end
end
Then, you can initialize the ‘configurations’ parameter using this validation function as shown:
properties (Access = private)
configurations (1,:) cell {validator}
end
2. You can create a validation check when adding a new configuration. Each configuration object will be validated during the addition process in the ‘Session’ class. Below is the implementation of an ‘addConfiguration’ function:
function addConfiguration(this, config)
mustBeA(config, 'Configuration');
this.configurations{end+1} = config;
end
With this approach, no validation is required in the properties section, configuration parameter can be defined as follows:
properties (Access = private)
configurations % No direct validation here
end
You can now create a ‘Session’ object and add multiple ‘Configuration’ class objects as required:
% Session object creation
session = Session();
% Add configuration objects (config1, config2) to the session
session.addConfiguration(config1);
session.addConfiguration(config2);
For more information, refer to the following MathWorks Documentation:
I hope this helps!
More Answers (2)
Matt J
on 3 Oct 2024
Edited: Matt J
on 3 Oct 2024
classdef Session < handle
%SESSION Summary of this class goes here
% Detailed explanation goes here
properties (Access = private)
configurations (1, :)
end
methods (Access = public)
function this = Session()
this.configurations = {};
end
function set.configurations(obj,val)
inputValid=iscell(val);
if inputValid && ~isempty(val)
inpuValid = all( cellfun( @(z)isa(z,'App.Core.Configuration') , val) );
end
assert(inputValid,"property value must be a cell array of 0 or more Configuration objects")
end
end
0 Comments
Steven Lord
on 3 Oct 2024
What's the default value for your property?
properties (Access = private)
configurations (1, :) cell {mustBeA(configurations, "App.Core.Configuration")}
end
The code you've written looks like the definition of Prop1 in the first code block on this documentation page. "The property definition does not specify a default value, so MATLAB initializes the property value to an empty double ([])." [Though actually that's not quite correct since you're using class validation as well, so as per the "Specify Valid Default" section on this documentation page, "If you do not specify a default value, MATLAB creates a default value by assigning an empty object of the specified class or by calling the default constructor if size restriction does not allow the use of an empty default value."]
Is that a valid value for your property? Since it is not (it fails the property validation function check), MATLAB correctly throws an error.
Error using implicit default value of property 'configurations' of class 'App.Core.Session'. Value must be one of the following types: 'App.Core.Configuration'.
Depending on the details of what the App.Core.Configurations class actually is, using App.Core.Configuration.empty() along the lines of the Prop4 definition might be an option (and defining configurations to be an array of that class rather than a cell array.) Though if it is a handle object as I suspect it is, see the "Handle Objects as Default Property Values" section on the first documentation page to which I linked.
2 Comments
Steven Lord
on 3 Oct 2024
configurations = cell(1, 0);
try
mustBeA(configurations, "App.Core.Configuration")
fprintf("mustBeA succeeded")
catch ME
fprintf("mustBeA threw error:\n%s", ME.message)
end
A cell array is not an App.Core.Configuration.
Even if you had a cell array containing an instance of a class, that doesn't make the cell array be an instance of that class. mustBeA checks for an is-a relationship not a contains-a relationship.
g = graph;
try
mustBeA(g, "graph") % Succeeds, g isa graph
fprintf("mustBeA succeeded")
catch ME
fprintf("mustBeA threw error:\n%s", ME.message)
end
gc = {g};
try
mustBeA(gc, "graph") % fails, gc isnota graph. gc containsa graph.
fprintf("mustBeA succeeded")
catch ME
fprintf("mustBeA threw error:\n%s", ME.message)
end
this logic works with other object types like the string, but not for my custom class.
You don't wrap a string in a cell array in your object. If you did you'd have the same contains-a versus is-a problem.
s = "abracadabra"; % is-a
try
mustBeA(s, "string")
fprintf("mustBeA succeeded")
catch ME
fprintf("mustBeA threw error:\n%s", ME.message)
end
sc = {s}; % contains-a
try
mustBeA(sc, "string")
fprintf("mustBeA succeeded")
catch ME
fprintf("mustBeA threw error:\n%s", ME.message)
end
See Also
Categories
Find more on Handle Classes in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!