Carlo
Carlo

Reputation: 185

How to create a "one-way dependency" within Matlab handle class

I am fairly new to Matlab, and I was wondering if there is a way to create a "one-way handle class".

To explain better, lets say I have a class called test_class, with properties "prop1" and "prop2"

test_1 = test_class(5,10)
test_2 = test_1

I wanted changes applied to properties within test_1 (parent) to affect test_2 (child), but I do not want changes in test_2 to affect test_1, so

test_1.prop1 = 20;
test_2.prop1: 20

test_2.prop2 = 30;
test_1.prop2: 5

Is there a way to create such a "one-way dependecy"?

Thanks in advance!

Upvotes: 4

Views: 89

Answers (3)

Andy Campbell
Andy Campbell

Reputation: 2187

You can do this without getting into the difficulties of subasgn by leveraging property set listeners. This way you don't need ot get in the business of holding on to and managing all of the children copies. This looks something like the following:

classdef test_class < matlab.mixin.Copyable

    properties(SetObservable)
        prop1
        prop2
    end

    properties
        prop3
    end

    methods
        function obj = test_class(in1, in2, in3)
            obj.prop1 = in1;
            obj.prop2 = in2;
            obj.prop3 = in3;
        end
        function ref = make_dependent_reference(obj)
            ref = copy(obj);

            cls = metaclass(obj);
            observableProps = cls.PropertyList.findobj('SetObservable',true);
            for ct =1:numel(observableProps)
                obj.addlistener(observableProps(ct).Name, 'PostSet', ...
                    @(prop,evd)ref.update_dependent_reference(prop,evd));
            end
        end
    end
    methods(Access=private)
        function update_dependent_reference(ref, prop, evd)
            ref.(prop.Name) = evd.AffectedObject.(prop.Name);
        end
    end
end

Note, this requires the properties to be SetObservable, you can either choose to make the reference updates to those properties ignore properties that are not SetObservable like I've shown above with the findobj call or you can instead operate on all properties and let the addlistener call error out for any properties that are not SetObservable.

>> t = test_class(5,10,15)

t = 

  test_class with properties:

    prop1: 5
    prop2: 10
    prop3: 15

>> ref = t.make_dependent_reference

ref = 

  test_class with properties:

    prop1: 5
    prop2: 10
    prop3: 15

>> ref.prop1 = 6

ref = 

  test_class with properties:

    prop1: 6
    prop2: 10
    prop3: 15

>> t

t = 

  test_class with properties:

    prop1: 5
    prop2: 10
    prop3: 15

>> t.prop2 = 11

t = 

  test_class with properties:

    prop1: 5
    prop2: 11
    prop3: 15

>> ref

ref = 

  test_class with properties:

    prop1: 6
    prop2: 11
    prop3: 15 

Upvotes: 4

rahnema1
rahnema1

Reputation: 15837

Here is a basic implementation. Each object has a parent and an array of children. Using subsasgn we can change properties of the object and its children and because the object is one-way we don't want to change properties of the parent.

Usage:

a = oneway(1,2);
b = oneway(a);
c = oneway(b);

If we set a.prop1 = 7; then b will be changed that leads to change of c. If you want only to change the direct children you can uncomment line 31 and comment line 30.

classdef oneway < handle
    properties
        parent
        children={};
    end
    properties
     prop1
     prop2
    end
    methods
        function obj = oneway(varargin)
            if nargin == 1
                a = varargin{1};
                if isa(a,'oneway')
                    obj.prop1 = a.prop1;
                    obj.prop2 = a.prop2;
                    obj.parent = a;
                    a.children{end+1} = obj;
                end
            elseif nargin == 2
                obj.prop1 = varargin{1};
                obj.prop2 = varargin{2};
            end
        end
        function obj = subsasgn(self, S, B)
            if strcmp(S.type, '.')
                if ismember(S.subs, properties(self))
                    obj = builtin('subsasgn', self, S, B);
                    for k = 1: numel(self.children)
                        self.children{k} = subsasgn(self.children{k},S,B);
                        %self.children{k} = builtin('subsasgn', self.children{k}, S, B);
                    end
                end
            end
        end
        function delete(self)
            self.parent.children (cellfun(@(x)x==self,self.parent.children))=[];
            for k = 1: numel(self.children)
                self.children{k}.parent =[];
            end
        end
    end
end

Upvotes: 3

Aero Engy
Aero Engy

Reputation: 3608

I don't think this is possible. You can either have copies of handle objects which refer to the same underlying object (2-way dependent) or value objects where copies are independent of each other. Object behavior.

You might be able to create value object which has a Property that contains a handle ... so part of the you object is 2-way and part is 1-way. But that isn't really what you asked for.

Upvotes: 0

Related Questions