Implementing an hgsetget subclass
Show older comments
>>u=unit('SI');
>>set(u) % set behavior 1
System: '[{SI} | cgs]'
>>set(u,'System') % set behavior 2
[{SI} | cgs]
>>set(u,'System','cgs') % set behavior 3
>>get(u,'System')
ans =
cgs
In other words, much like the behavior you see for a figure handle. Following the example in Implementing a Set/Get Interface for Properties, I tried this code:
classdef unit < hgsetget
properties
System = '';
end
methods
function H = unit(str)
if nargin > 0
H.System = str;
end
end
function H = set.System(H,str)
H.System = str;
end
end
end
This gets set behavior 3 right, but how do I add the other two? The closest I have come so far is to simply program all the cases into an overloaded set method, and get rid of set.System. But if I add a few more properties, this gets quite ugly. Does anyone know an elegant way of doing this?
Accepted Answer
More Answers (3)
Jiro Doke
on 26 Feb 2011
This is interesting. It does seem like the documentation isn't complete. It mentions how calling the set with a particular syntax returns the possible values of a property, but it doesn't explain how to specify those possible values.
Here's something that I put together to try to achieve what you want, while making it somewhat extensible to multiple properties:
classdef MyClass < hgsetget
properties
Prop1
Prop2
end
properties (Hidden, Constant)
Prop1_values = {'SI', 'cgs'}
Prop2_values = {'C', 'F'}
end
methods
function varargout = set(obj, varargin)
% Allow only one output and no more than 3 input arguments
error(nargoutchk(0, 1, nargout, 'struct'));
error(nargchk(1, 3, nargin, 'struct'));
switch nargin
case 1 % set(h) syntax
propnames = properties(obj);
if nargout
s = cell2struct(cell(size(propnames)), ...
propnames, 1);
for id = 1:length(propnames)
s.(propnames{id}) = set(obj, propnames{id});
end
varargout{1} = s;
else
for id = 1:length(propnames)
set(obj, propnames{id});
end
end
case 2 % set(h, 'PropertyName') syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
if nargout
varargout{1} = MyClass.([varargin{1}, '_values']);
else
fprintf('%10s: %s\n', varargin{1}, ...
toString(MyClass.([varargin{1}, '_values'])));
end
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
case 3 % set(h, 'PropertyName', value) syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
val = validatestring(varargin{2}, ...
MyClass.([varargin{1}, '_values']), ...
mfilename, varargin{1});
obj.(varargin{1}) = val;
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
if nargout
varargout{1} = [];
end
end
end
end
end
function str = toString(in)
in{1} = ['{', in{1}, '}']; % first input is the default
str = sprintf('| %s ', in{:});
str = ['[', str(2:end), ']'];
end
I have Hidden, Constant properties that specify the possible property values, and the set method queries that information. So whenever I create a new property, I create a corresponding Prop#_values property.
EDIT: I've implemented a Setter for the properties. In this example, instead of creating a separate Setter method for each property, I made it as a part of the set method (see case 3 in the switch statement). Since the Prop#_values contain the valid string values, I use that to validate the input.
Test...
>> a = MyClass;
>> set(a)
Prop1: [ {SI} | cgs ]
Prop2: [ {C} | F ]
>> set(a, 'Prop2')
Prop2: [ {C} | F ]
>> set(a, 'Prop1', 'cgs')
>> get(a, 'Prop1')
ans =
cgs
>> set(a, 'Prop2', 'CF')
??? Error using ==> MyClass
Expected Prop2 to match one of these strings:
C, F
The input, 'CF', did not match any of the valid strings.
Error in ==> MyClass>MyClass.set at 46
val = validatestring(varargin{2}, ...
>>
7 Comments
Andrew Newell
on 26 Feb 2011
Jiro Doke
on 26 Feb 2011
@Andrew: I modified my answers to include set validation. Instead of creating a separate setter method, I do it inside the "set" method. I use Prop#_value property to validate the input.
I see your question about the advantage of using hgsetget. I honestly don't know, and I'm asking around to see if someone has a good explanation. I'll post here once I hear something.
Andrew Newell
on 26 Feb 2011
Jiro Doke
on 26 Feb 2011
@Andrew: Yes, I would normally use set.Prop methods for each method. In this case, I assumed all the properties accept only strings from a cell array of strings. So I put it all in the set method.
"validatestring" is only for selecting from a selection of strings. You may also want to look at "validateattributes".
Andrew Newell
on 27 Feb 2011
Jiro Doke
on 28 Feb 2011
@Andrew: That's great! Would you care to share that on the File Exchange? It seems like there is no simple way of doing it with HGSETGET, so your approach might be the best currently.
Andrew Newell
on 28 Feb 2011
Andrew Newell
on 25 Feb 2011
Andrew Newell
on 10 Mar 2011
0 votes
Categories
Find more on Argument Definitions 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!