Function Argument Validation from Class Properties ignores defaults
7 views (last 30 days)
Show older comments
This question is about function argument validation, based on the structname.?ClassName synthax as provided by Mathworks here. We're running R2020b - 9.9.0.1467703 (aug 2020, so I suspect 'Update 0'). First off, let me say I am a huge fan of the Arguments block, thank you so much Mathworks!
Context: we have multiple functions that at some point pass inputs to a set of classes with particular options. The intention is to define the name-value pairs once, and reuse that definition. This is opposed to copy-pasting parts of an arguments block, with the associated validation functions and defaults. Much neater to define once, and prevent a mess of different defaults, validations and such small differences. It also makes it much easier to update the whole family of function.
Issue: So we've defined one class to carry these options, their validation and defaults. Unfortunately the defaults appear not to be pass from the class defining the name-value paris.
Example code
file: TestInput.m
function TestInput(local, fromclass)
arguments
local.one (1,1) double = pi
local.two (1,:) char {mustBeMember(local.two, {'a', 'bb', 'ccc'})} = 'ccc'
fromclass.?DefineArg % crucial part where name-values are pulled from classdef
end
% show
local % default available
fromclass % no defaults available, despite class defining them
end
file: DefineArg.m
classdef DefineArg
properties
Exquise (1,1) double {mustBeNonnegative, mustBeInteger} = 3
Expletive (1,:) char {mustBeMember(Expletive, {'ai', 'caramba'})} = 'caramba'
end
end
Running the following code gives an empty fromClass struct:
Question: any way to also get the defaults? So far we get the name, size, class, validation but not the defaults!? I suppose you often don't want this, but it might be really nice to be able to turn this on.
ps: note how nicely the autocomplete works, including the valid inputs.
0 Comments
Accepted Answer
Aghamarsh Varanasi
on 9 Mar 2021
Edited: Aghamarsh Varanasi
on 9 Mar 2021
Hi,
As of R2020b, meta class operator '?' can be used to validate function arguments. It does not support assignment of default arguments from meta.class. As a work-around you can assign the default values of the meta.class arguments to the function arguments after the validation as follows.
function TestInput(local, fromclass)
arguments
local.one (1,1) double = pi
local.two (1,:) char {mustBeMember(local.two, {'a', 'bb', 'ccc'})} = 'ccc'
fromclass.?DefineArg % crucial part where name-values are pulled from classdef
end
if isempty(fields(fromclass)) % ensure fromclass is empty
% assign default values to name-value pairs
metaClass = metaclass(DefineArg);
for i = 1:numel(metaClass.PropertyList)
prop = metaClass.PropertyList(i);
if prop.HasDefault
fromclass.(prop.Name) = prop.DefaultValue;
end
end
end
% show
local % default available
fromclass % no defaults available, despite class defining them
end
More Answers (1)
Youssif Mosa
on 31 Mar 2023
Edited: Youssif Mosa
on 31 Mar 2023
Version 2022a still does not have this feature :(
I do not know about later versions but here is an elegant refactor for the same answer from @Aghamarsh Varanasi
function TestInput(local, fromclass)
arguments
local.one (1,1) double = pi
local.two (1,:) char {mustBeMember(local.two, {'a', 'bb', 'ccc'})} = 'ccc'
fromclass.?DefineArg % crucial part where name-values are pulled from classdef
end
fromclass=autoFillDefaults(fromclass,?DefineArg); % Just add this line after the arguments block
% show
local % default available
fromclass % now this also have default values
end
The function autoFillDefaults() can be in a separate file for reuse, you will need to add just one like after the arguments block.
This function will autofill the default values only for the arguments not provided on the function call.
function fromclass = autoFillDefaults(fromclass,metaClass)
arguments
fromclass struct
metaClass meta.class
end
p=metaClass.PropertyList;
for n=1:length(p)
if p(n).HasDefault && ~isfield(fromclass,p(n).Name)
fromclass.(p(n).Name)=p(n).DefaultValue;
end
end
end
1 Comment
Aliasghar
on 7 Oct 2024
unfortunately, this only works when the default vlue is assigned to the property of the superclass. Not if the default value is only defined in the arguments block of the constructor or static method(s).
See Also
Categories
Find more on Class File Organization in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!