Creating a hard link among properties of an object?

Hello,
I have a class called Module that has 3 properties: InternalVariables, ExternalVariables, and AllVariables. InternalVariables and ExternalVariables both contain symbolic column vectors. I want to define AllVariables as the superposition of InternalVariables and ExternalVariables, and if I change either InternalVariables or ExternalVariables, AllVariables gets updated automatically. Is there a way to do this by using a hard link?
Thank you,
Kevin

 Respuesta aceptada

Sean de Wolski
Sean de Wolski el 13 de Mayo de 2014

0 votos

A couple of thoughts
Why not just make AllVariables a dependent property. Then every time it's queried it's calculated on the fly. MATLAB passes by reference so unless you have thousands of variables this should not be a performance penalty.
Another approach would be with listeners. The basic plan would be to have the constructor set listeners for changes to internal and external properties. This avoids having to have an explicit setter for each property. Of course, having an explicit setter for each property isn't necessarily a bad thing, especially if you need to validate the new property values anyway. In fact, I would probably just take this approach and use a setter every time.

4 comentarios

Cedric
Cedric el 13 de Mayo de 2014
Editada: Cedric el 13 de Mayo de 2014
The way I understood the question, the OP stores what he calls internal and external variables in structs. I don't think that we can get the field name in a getter/setter, and if this is true, we cannot address the relevant struct (the one which has the field) when allVars is accessed.
We can query fieldnames (dynamically or not) of the structs as necessary. Why wouldn't this be possible in a setter or getter?
Cedric
Cedric el 13 de Mayo de 2014
Editada: Cedric el 13 de Mayo de 2014
I built really fast a dummy example to illustrate
classdef TestClass < handle
properties
intVars
extVars
allVars
end
methods
function obj = TestClass()
obj.intVars = struct( 'a', 8:15, 'b', -3 ) ;
obj.extVars = struct( 'c', 7, 'd', 8 ) ;
end
function value = get.intVars( obj ), value = obj.intVars ; end
function set.intVars( obj, value ), obj.intVars = value ; end
function value = get.extVars( obj ), value = obj.extVars ; end
function set.extVars( obj, value ), obj.extVars = value ; end
function value = get.allVars( obj )
% If accessing e.g. TestClass.allVars.c, how do I know here
% that field 'c' was addressed => how can I pick extVars?
end
function set.allVars( obj, value )
% If accessing e.g. TestClass.allVars.c, how do I know here
% that field 'c' was addressed => how can I pick extVars?
end
end
end
On that note, have a good night! I'll be back tomorrow to go on the discussion.
I don't have much time right now (so will probably have to continue this tonight) but here the better of the two approaches I had in mind:
In the getter (recommended!)
classdef TestClass < handle
properties
intVars
extVars
end
properties (SetAccess = protected, Transient = true, Dependent = true)
allVars
end
methods
function obj = TestClass()
obj.intVars = struct( 'a', 8:15, 'b', -3 ) ;
obj.extVars = struct( 'c', 7, 'd', 8 ) ;
end
function val = get.allVars(obj)
val = obj.intVars;
fns = fieldnames(obj.extVars);
for ii = 1:numel(fns)
val.(fns{ii}) = obj.extVars.(fns{ii});
end
end
end
end
To use it:
T = TestClass
T.allVars
T.intVars.Hwllo = pi
T.allVars
T.extVars.World = exp(1)
T.allVars

Iniciar sesión para comentar.

Más respuestas (1)

Cedric
Cedric el 12 de Mayo de 2014
Editada: Cedric el 13 de Mayo de 2014
NOTE: well, I spent an hour stuck in a mall with a tornado warning, so I had a little time to extend my first example. See EDIT below.
Did you try using setters and getters for these properties (in conjunction with dependent properties)? If they are stored in structs (and not as public/private/etc groups of properties), you may have to use subsasgn / subsref / substruct, etc.
EDIT : here is a new version of my previous example, which delegates indexing appropriately (I suppose, but I didn't have time to test) when fields of allVars contain arrays or structs.
classdef TestClass < handle
properties
intVars
extVars
allVars
end
methods
function obj = TestClass()
obj.intVars = struct( 'aInt', 3, 'bInt', 20:30, 'c', 7 ) ;
obj.extVars.dExt = struct( 'x', -2, 'y', 48 ) ;
obj.extVars.eExt = {'Hello', 'World'} ;
obj.extVars.c = 8 ;
end
function value = subsref( obj, S )
if length(S) > 1 && all( [S(1:2).type] == '.' ) && ...
strcmp( S(1).subs, 'allVars' )
is_int = isfield( obj.intVars, S(2).subs ) ;
is_ext = isfield( obj.extVars, S(2).subs ) ;
if is_int && is_ext
valueInt = obj.subsref_delegate( obj.intVars.(S(2).subs), S ) ;
valueExt = obj.subsref_delegate( obj.extVars.(S(2).subs), S ) ;
value = struct( 'int', valueInt, 'ext', valueExt ) ;
elseif is_int
value = obj.subsref_delegate( obj.intVars.(S(2).subs), S ) ;
else
value = obj.subsref_delegate( obj.extVars.(S(2).subs), S ) ;
end
else
value = builtin( 'subsref', obj, S ) ;
end
end
function obj = subsasgn_TODO( obj, S, value )
% .. your move.
end
end
methods (Static)
function value = subsref_delegate( x, S )
if length( S ) > 2
value = builtin( 'subsref', x, S(3:end) ) ;
else
value = x ;
end
end
end
end
With that..
>> tc = TestClass() ;
>> tc.intVars
ans =
aInt: 3
bInt: [20 21 22 23 24 25 26 27 28 29 30]
c: 7
>> tc.extVars
ans =
dExt: [1x1 struct]
eExt: {'Hello' 'World'}
c: 8
>> tc.extVars.dExt.x
ans =
-2
>> tc.allVars.aInt
ans =
3
>> tc.allVars.bInt
ans =
20 21 22 23 24 25 26 27 28 29 30
>> tc.allVars.bInt(7)
ans =
26
>> tc.allVars.c % c is a common property => output struct with int/ext values.
ans =
int: 7
ext: 8
>> tc.allVars.eExt{2}
ans =
World
>> tc.allVars.dExt.y
ans =
48

4 comentarios

How can I use that to not have to re-assign AllVariables every time InternalVariables or ExternalVariables are changed? Can you give me a simple example?
Cedric
Cedric el 12 de Mayo de 2014
Editada: Cedric el 13 de Mayo de 2014
Just edited my answer with an example. If it answers your question, still wait a day or so before accepting the answer, as others (like Matt J) might have good insights and/or a better approach to propose.
PS: you probably understood that we are overloading subsref and subsasgn, to catch accesses to allVars's fields. If you don't understand how this works, create the object tc:
>> tc = TestClass() ;
and place a break point at the beginning of subsref (place cursor on the line which starts with if length( S ) .., and press F12). Then evaluate
>> tc.intVars.aInt
Once in the debugger, look at the struct S and you will understand the logic (if not, ask me again). Note that the else clause, which is evaluated in situations that we don't want to manage (i.e. when the user is not indexing a field of allVars), with the call
... = builtin( 'subsref', ..
is just delegating the management of the indexing to the builtin subsref (meaning not our overloaded version).
Interesting comment on the tornado warning - I wonder if it was the same one that kept me at the hotel yesterday outside of Detroit.
Cedric
Cedric el 14 de Mayo de 2014
Ah! Yes, I am in Ann Arbor ;-)

Iniciar sesión para comentar.

Categorías

Más información sobre Customize Object Indexing en Centro de ayuda y File Exchange.

Preguntada:

el 12 de Mayo de 2014

Comentada:

el 14 de Mayo de 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by