Question

I have a MATLAB class called super:

classdef super < handle

    properties
        aString = '';
    end

    methods
        function obj = super(obj, value)
            obj.aString = value;
        end

        function set.aString(obj, value)
            obj.aString = value;
        end
    end
end

I want to override the set function in a subclass derived from 'super':

classdef sub < super

    %// Property 'aString' is inherited from super

    methods
        function obj = sub(obj, value)
            %// Must include call to super constructor otherwise MATLAB will by
            %// default call constructor with no arguments but my super class
            %// requires one argument in constructor. This call should probably
            %// super set method. But I don't care.
            obj = obj@super('');

            %// Now that super constructor has returned, call sub overriding
            %// set method
            obj.aString = value;

        end

        function set.aString(obj, value)
            obj.aString = value;
        end
    end
end

The code above gives me the following error:

> Cannot define property 'aString' in class 'sub' because the property
> has already been defined in the superclass 'super'

Adding the property definition to 'sub' results in the same error.

I have also unsuccessfully tried using "Abstract" as a workaround, where I define an Abstract class:

classdef (Abstract) bloat < handle
    properties (Abstract)
        aString
    end
end

and then try implementing 'super' as a child of 'bloat':

classdef super < bloat
%// Remainder of super code remains the same

Which did not work as I guess by the time 'sub' inherites, 'aString' is "concrete". I then, in addition to the above modification, tried modifying 'sub' to include 'boat' in its class definition:

classdef sub < super & bloat
%// Remainder of super code remains the same

This also did not work.

I have been unable to find any MATLAB documentation that specifically says: "You cannot modify set and get methods".

I'm hoping that my syntax is simply incorrect, but from searching I now fear that MATLAB does not allow this (either as a bug or by design).

EDIT: I am using MATLAB 2013a

Thank you

Was it helpful?

Solution

Another solution is to make the set method call a protected function to perform whatever logic you need on assignment. This protected method can of course be overriden in subclasses.

Although unrelated to the issue above, it is always preferable to have a constructor that accepts zero arguments as well your current constructor. See the changes I made in that regard.

super.m

classdef super < handle
    properties
        x = 1;    % some property with a default value
    end

    methods
        function obj = super(value)
            % allow for zero-argument construction
            if nargin > 0
                obj.x = value;
            end
        end
        function set.x(obj, value)
            % call another function to check the value as desired,
            % and possibly even update it using some computation
            value = checkX(obj, value);

            % set set the property using the validated value
            % (only place we do assignment to avoid infinite recursion)
            obj.x = value;
        end
    end

    methods (Access = protected)
        function value = checkX(obj, value)
            % for example, we require that values be scalar positive
            validateattributes(value, {'numeric'}, {'scalar','positive'});
        end
    end
end

sub.m

classdef sub < super
    methods
        function obj = sub(value)
            % set inherited property if requested
            if nargin > 0
                obj.x = value;
            end
        end
    end

    methods (Access = protected)
        function value = checkX(obj, value)
            % we could call superclass method to combine effect
            value = checkX@super(obj, value);

            % or override super-class logic (example: maximum value of 10)
            value = min(value,10);
        end
    end
end

OTHER TIPS

You will have to have your set method call a different method which you then can overload. This requires you to make aString dependent, and store its value somewhere else to avoid infinite recursions.

classdef super < handle

    properties (Dependent)
        aString
    end
    properties (Hidden)
        storeAString = '';
    end

    methods
        function obj = super(obj, value)
            obj.aString = value;
        end

        function set.aString(obj, value)
            setString(obj,value);
        end
        function value = get.aString(obj)
            value = obj.storeAString;
        end
    end
    methods (Hidden)
        function setString(obj,value)
            %# this is the method you will be able to overload
            obj.storeAString = value;
        end
    end
end

First, since the question includes request for a reference to the Matlab documentation:

The Matlab documentation on Property Access Methods states (currently for rev. 2015a):

You can define property access methods only:

  • For concrete properties (that is, properties that are not abstract)
  • Within the class that defines the property (unless the property is abstract in that class, in which case the concrete subclass must define the access method).

So it seems overriding get/set-methods is not possible by design.


Second, here is another quirky workaround: One can make a property observable and in the event notifier change the value. So in the super class we set the SetObservable flag:

super.m:

classdef super < handle

  properties (SetObservable)
      aString;
  end

  methods
    function obj = super(value)
        obj.aString = value;
    end

    function set.aString(obj, value)
        obj.aString = value;
    end
  end
end

And in the sub class a listener is introduced in the constructor. It points to a function which is called whenever the property value is assigned. The function then checks the value (and corrects/changes it when necessary).

sub.m:

classdef sub < super

    %// Property 'aString' is inherited from super

    methods
        function obj = sub(value)
            %// Must include call to super constructor otherwise MATLAB will by
            %// default call constructor with no arguments but my super class
            %// requires one argument in constructor. This call should probably
            %// super set method. But I don't care.
            obj = obj@super('');

            %// Now that super constructor has returned, call sub overriding
            %// set method
            obj.aString = value;
            addlistener(obj, 'aString', 'PostSet',@obj.checkAString);
        end
        function checkAString(self, ~, ~)
            if isempty(self.aString)
                self.aString = 'was empty';
            end;
        end
    end
end

if you then run

a_sub = sub('');
a_sub.aString = ''

You'll get:

a_sub = 

  sub with properties:

    aString: 'was empty'

as a result.

However, this is not an ideal solution either. There are at least these drawbacks:

  • The input to the listener is different from the input of the set routine. So, if, f.ex. the original value was overwritten, the original value is no longer available (OK, one could have a aString_backup variable which is then stored on a GetObservable event but that gets even more complicated).
  • I would assume the order in which the listeners are called can be random. Thus, if one has more than one listener it is not certain which one of them is run first.
  • I guess there is a performance penalty when using listeners on properties which are frequently read/written
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top