Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot set attributes #96

Open
paulbareilCodotek opened this issue Dec 1, 2021 · 7 comments
Open

Cannot set attributes #96

paulbareilCodotek opened this issue Dec 1, 2021 · 7 comments

Comments

@paulbareilCodotek
Copy link

Hi, I cannot set attributes if the class does not import mixin. The following matlab TestObject is in a @TestObject folder and TestObject.m file. I can create an instance of this class in Matlab and change the attribute. I can do:

test = TestObject(2); and if I print test.attribute, it returns 2. If I then do test.attribute = 3;, it will change its value.

However, doing this in Python does not work. The values stays at 2. If I change the Matlab class header to classdef TestObject < matlab.mixin.Copyable, then it works. However, I need to interface to matlab code that does not implement the mixin class. How can I change the attribute of the Matlab class then?

`classdef TestObject
properties

    attribute        = 12345;
    
end

methods
    
    function obj = set.attribute(obj, value)
        obj.attribute = value;
    end
    function obj = TestObject(value)
        
        
        if nargin == 1
            obj.attribute = value;
            
        else
            error('Provide value')
        end
    end
    
end

end`

@bastibe
Copy link
Owner

bastibe commented Dec 1, 2021

Honestly, I have no idea. Transplant doesn't do anything crazy, though: It calls subsasgn on the object, nothing more.

Does your class work with subsasgn?

@paulbareilCodotek
Copy link
Author

paulbareilCodotek commented Dec 1, 2021

I was able to debug the Python and Matlab code. I haven't found the exact source of the problem yet, still trying to wrap my head around the way it works. But from what I understand, the problem is the 'del proxy'

The python code below calls matlab with the substruct function to get the structure necessary to make the call, then the subsasgn makes the call correctly and somewhere in the process, on the Matlab side, a new proxied_objects object is created at the last cell array index.

access = MatlabStruct(self.process.substruct('.', name))
self.process.subsasgn(self, access, value)

That new proxied_object is correct. It has the changed value. However, when the following function is called, the object we just created and modified is deleted.

def __del__(self): self.process._del_proxy(self.handle)

I do not know yet why the del function is called and why a new proxied_objects is created instead of being modified, but the problem lies there. It also explains why a copyable mixin class has no problem since the copy is shallow.

@paulbareilCodotek
Copy link
Author

paulbareilCodotek commented Dec 1, 2021

Got it. The self.process.subsasgn(self, access, value) line actually returns the new modified object. As in the Matlab object we have to return the object itself.

function obj = set.attribute(obj, value)

        `obj.attribute = value;

    end`

While, when subclassing < matlab.mixin.Copyable there is a warning saying "Set function in handle class does not need to return the modified object."

So the actual modified object is discarded right now, but when trying this directly in Matlab it seems to automatically reapply the object.
It is actually a big problem because if I create an object testObject = TestObject() and then re-use that object accross different other objects, none of them will see the change because a different copy would have been created.

Do you see any way to go around this? Other than < matlab.mixin.Copyable I mean?

@bastibe
Copy link
Owner

bastibe commented Dec 7, 2021

Thank you for your analysis! That sounds like a nasty problem. If I understand you correctly, Copyable classes behave differently than non-Copyable classes to subsasgn.

I think we would have to (conditionally?) overwrite self.process in __setattr__. Can we do that in every case, or only for one of the Copyable/non-Copyable?

In either case, I'm afraid I don't have access to Matlab any longer, which means I can't test any changes myself. But I'll happily review and accept a pull request!

@paulbareilCodotek
Copy link
Author

Yes that seems to be the case. I will investigate a little further on the Matlab side to be sure to understand the problem correctly. You built such a good package, I feel like I have to contribute a little if I can. I do not have much time, but will come back on this.

@paulbareilCodotek
Copy link
Author

ok, I made some quick Matlab tests If you have the following class in Matlab

`classdef TestObject

properties
    attribute = 123456;
    ref_obj;
end
methods
    function obj = set.attribute(obj, value)
        obj.attribute = value
    end
    function obj = set.ref_obj(obj, value)
        obj.ref_obj = value
    end
    function obj = TestObject(value)
        obj.attribute = value;
    end
end

end`

Then if you create 2 objects and reference it on the second object

test = TestObject(1);
test2 = TestObject(2);
test2.ref_obj = test;

If you do
test.attribute = 10;
test2.ref_obj will return 1

!!!. So the problem is NOT transplant.

It seems Matlab "standard" classes cannot be referenced! Making it inherit copy was not a requirement, it need at least to inherit from "handle" to work as a referenceable class. https://www.mathworks.com/help/matlab/handle-classes.html

@bastibe
Copy link
Owner

bastibe commented Dec 13, 2021

Oh, Matlab! I do wonder what considerations and constraints have lead to the maze of curveballs that is the Matlab object system.

At any rate, thank you for sharing your analysis. I find it oddly satisfying to dive deeply into strange code such as Matlab's.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants