9

Writing a subclass of dynamicprops allows to me to add properties dynamically to an object:

addprop(obj, 'new_prop')

This is great, but I would also love to create set / get functions for these properties on the fly. Or analysis functions that work on these dynamic properties.

My experience with Matlab has been so far, that once I create an instance of a class, adding new methods is not possible. That is very cumbersome, because my object may contain a lot of data, which I'll have to re-load every time that I want to add a new method (because I have to do clear classes).

So is there a way to add methods on the fly?

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
memyself
  • 11,907
  • 14
  • 61
  • 102
  • You can add new methods as long as you do clear classes afterwards, but you want to get around it. I don't think that will work in general. –  Aug 08 '12 at 10:51

3 Answers3

10

You cannot add methods like you add dynamic properties. However, there are two ways for implementing new methods during development that won't require you to re-load the data every time.

(1) I write standard methods as separate functions, and call them as myMethod(obj) during development. Once I'm sure they're stable, I add their signature into the class definition file - this requires a clear classes, of course, but it is a much delayed one, and from time to time you may have to shut down Matlab, anyway.

(2) With set/get methods, things are a little trickier. If you are using dynamicprops to add new properties, you can also specify their set/get methods, however (most likely, these methods/functions will want to receive the name of the property so that they know what to refer to):

addprop(obj,'new_prop');
prop = findprop(obj,'new_prop');
prop.SetMethod = @(obj,val)yourCustomSetMethod(obj,val,'new_prop')

EDIT

(2.1) Here's an example of how to set up a hidden property to store and retrieve results (based on jmlopez' answer). Obviously this can be improved a lot if you have a better idea what you're actually designing

classdef myDynamicClass < dynamicprops
    properties (Hidden)
        name %# class name
        store %# structure that stores the values of the dynamic properties
    end
    methods
        function self = myDynamicClass(clsname, varargin)
            % self = myDynamicClass(clsname, propname, type)
            % here type is a handle to a basic datatype.
            self.name_ = clsname;
            for i=1:2:length(varargin)
                key = varargin{i};
                addprop(self, key);
                prop = findprop(self, key);
                prop.SetMethod = @(obj,val)myDynamicClass.setMethod(obj,val,key);
                prop.GetMethod = @(obj)myDynamicClass.getMethod(obj,key);
            end
        end
        function out = classname(self)
            out = self.name_;
        end
    end
    methods (Static, Hidden) %# you may want to put these in a separate fcn instead
        function setMethod(self,val,key)
           %# have a generic test, for example, force nonempty double
           validateattributes(val,{'double'},{'nonempty'}); %# will error if not double or if empty

           %# store
           self.store.(key) = val;

        end
        function val = getMethod(self,key)
           %# check whether the property exists already, return NaN otherwise
           %# could also use this to load from file if the data is not supposed to be loaded on construction 
           if isfield(self.store,key)
              val = self.store.(key);
           else
              val = NaN;
           end
        end
    end
end
Community
  • 1
  • 1
Jonas
  • 74,690
  • 10
  • 137
  • 177
  • so `myMethod` will actually be a generic function (and not a class method) that you can change as you like, right? – memyself Aug 08 '12 at 11:46
  • 1
    @memyself: exactly. Afterward, you can either copy `myMethod` into the classdef file, or simply add the signature to the classdef file and move `myMethod` into the class folder. – Jonas Aug 08 '12 at 12:17
  • @Jonas, is it possible to know what property we are trying to change from within `yourCustomMethod`? In the example you provided we may have something like `obj.new_prop = val;` to set the value. Can we access the property name somehow? – jmlopez Dec 28 '13 at 01:10
  • @jmlopez: you're right, of course. You most likely have to explicitly pass the property name to the method. – Jonas Dec 28 '13 at 09:17
  • Nice edit. I'm a little confused about this notation though: `@(obj,val)myDynamicClass.setMethod(obj,val,key)`. Does this mean that I can do something like: `@(obj, val)setMethod(obj, val, arg1, arg2, arg3, ...)`? What does that mean? Is this some sort of function casting? – jmlopez Dec 29 '13 at 04:05
  • 1
    @jmlopez: `@(obj,val) is an anonymous function that calls `setMethod` with the arguments `obj,val`. Upon construction, `arg1` etc are defined in the current workspace, and will passed along to `setMetod` once it is called. – Jonas Dec 29 '13 at 07:38
3

I'm adding this answer because I think that this is not intuitive. At least not to myself at this moment. After finding this question I thought I had what I needed to be able to define the set/get methods for my dynamic class. All I wanted to achieve with this was something similar to what python does with its __setattr__ method. In any case, here is a continuation of the class made by @jonas a while ago with a few modifications to add the our custom set method.

classdef myDynamicClass < dynamicprops
    properties (Hidden)
        name_ %# class name
    end
    methods
        function self = myDynamicClass(clsname, varargin)
            % self = myDynamicClass(clsname, propname, type)
            % here type is a handle to a basic datatype.
            self.name_ = clsname;
            for i=1:2:length(varargin)
                key = varargin{i};
                addprop(self, key);
                prop = findprop(self, key);
                prop.SetMethod = makefunc(key, varargin{i+1});
            end
        end
        function out = classname(self)
            out = self.name_;
        end
    end
end

function h = makefunc(key, argtype)
    h = @newfunc;
    function newfunc(obj, val)
       obj.(key) = argtype(val); 
    end
end

With this class I'm defining the set method so that the parameter passed to the attribute is copied to the right type. To see what I mean consider the following usage:

>> p_int = myDynamicClass('Point', 'x', @int8, 'y', @int32);
>> p_int.x = 1000 

p_int = 

  myDynamicClass with properties:

    y: []
    x: 127

>> class(p_int.x)

ans =

int8

With this we have forced the x attribute to be an integer of 8 bits which can only hold integers from -128 to 127. Also notice how the class of each attribute gives us the intended type.

Community
  • 1
  • 1
jmlopez
  • 4,853
  • 4
  • 40
  • 74
  • 1
    This is correct. Note that when defining custom set/get methods, you may run into the risk of infinite recursions, since the Matlab parser will not always know to avoid calling the set method as you assign the value of the property. To make your life easier (also for debugging purposes), it may be helpful to have a hidden property to store the values, that is then accessed by the getter/setter methods. – Jonas Dec 28 '13 at 09:19
  • 1
    @Jonas great comment - could you elaborate a bit more on the hidden property and how to implement this? – memyself Dec 28 '13 at 13:40
  • @Jonas, so similar to python `__dict__` variable. They mention the possibility of infinite recursion [here](http://docs.python.org/2/reference/datamodel.html#object.__setattr__). Is there some documentation about matlab that explains how to do this? – jmlopez Dec 28 '13 at 15:29
  • @memyself, jmlopez: I have updated my answer with an example. – Jonas Dec 28 '13 at 22:14
2

My experience with Matlab has been so far, that once I create an instance of a class, adding new methods is not possible. That is very cumbersome, because my object may contain a lot of data, which I'll have to re-load everytime that I want to add a new method (because I have to do clear classes).

It's worth noting for present-day readers of this question that this is no longer true. As of MATLAB R2014b MATLAB updates class definitions at the moment you save them, and the behaviour of existing class instances automatically updates accordingly. In the case of adding new methods, this is uncomplicated: the new method simply becomes available to call on class instances even if they were created before the method was added to the class.

The solutions given for choosing set/get methods for dynamic properties still apply.

There are still cases where you might want to add methods to an instance dynamically and the method doesn't constitute a property set/get method. I think the only answer in this case is to assign a function handle as the value to a dynamic property. This doesn't create a bona fide method, but will allow you to call it in the same way you would a method call:

addprop(obj, 'new_method');
obj.new_method = @(varargin) my_method(obj,varargin{:});

Calls to obj.new_method(args) are thus passed to my_method; however this only works with a scalar obj; an array of instances will have separate values for the new_method property so obj.new_method no longer resolves to a single function handle that can be called if obj is an array.

Will
  • 1,835
  • 10
  • 21