I need a particular class to expose a private static function. I do this via an anonymous function stored in a cell array. The contrived example below illustrates the issue:
classdef ParamClass
properties (Constant)
param_spec = {
{'param_1', @(x) isnumeric(x) && isscalar(x) && (x > 0)}, ...
{'param_2', @(x) ParamClass.validate_param_2(x)} ...
};
end
properties
param_1;
param_2;
end
methods (Static, Access = 'private')
function ok = validate_param_2(x)
ok = isnumeric(x) && isscalar(x) && (x < 0);
end
end
methods
function obj = ParamClass(p1, p2)
opts = parse_my_args(p1, p2, ParamClass.param_spec{:});
obj.param_1 = opts.param_1;
obj.param_2 = opts.param_2;
end
end
end
function opts = parse_my_args(p1, p2, varargin)
assert(varargin{1}{2}(p1));
assert(varargin{2}{2}(p2));
opts.param_1 = p1;
opts.param_2 = p2;
end
The function ParamClass.validate_param_2
is private static, but I want it to be called by an outside standalone function via the anonymous function wrapper. However I get the following error:
Error using ParamClass.validate_param_2
Cannot access method 'validate_param_2' in class 'ParamClass'.
After some thought, the error seems unnecessary. The class passes a function handle to the outside. The contents of the handle should be a matter only for the class to decide and should not be anyone's business. Should not all the required context for validate_param_2
be part of the anonymous function? Of course I can remove the error by making validate_param_2
public, but I would like to understand the rationale behind the error.
Any comments explaining why this kind of error is needed would be appreciated. Also any alternatives?
This is indeed a strange error, and I don't think it makes much sense. One explanation could be that while the property constraints are being evaluated, the class definition is not yet complete in memory, and the function ParamClass.validate_param_2()
is not yet available. But again, there is no reason for it to be this way, it might not have been a conscious choice (i.e. it's a bug).
As an alternative, you could instead use a local function (i.e. a function defined after the classdef
block, in the same file). Such a function is visible only from within the file, but you can return a handle to it, to make it useable from another file. This local function also has access to private members of the class. For all intents and purposes it is a private member, except it's only visible from within the file—class methods defined in the @ParamClass
directory will not be able to see it.
classdef ParamClass
properties (Constant)
param_spec = {
{'param_1', @(x) isnumeric(x) && isscalar(x) && (x > 0)}, ...
{'param_2', @validate_param_2} ...
};
end
properties
param_1;
param_2;
end
methods
function obj = ParamClass(p1, p2)
opts = parse_my_args(p1, p2, ParamClass.param_spec{:});
obj.param_1 = opts.param_1;
obj.param_2 = opts.param_2;
end
end
end
function opts = parse_my_args(p1, p2, varargin)
assert(varargin{1}{2}(p1));
assert(varargin{2}{2}(p2));
opts.param_1 = p1;
opts.param_2 = p2;
end
function ok = validate_param_2(x)
ok = isnumeric(x) && isscalar(x) && (x < 0);
end