Inheritance, abstract and constant properties.

4 views (last 30 days)
I am trying to write some classes that encapsulate concept definitions, but I'd also like to be able to define an alternate set of constant values for some of the properties.
At present, I have the following, and it works:
classdef my_supr (Abstract)
properties (Abstract, Constant)
foo;
baz;
end
end
classdef my_sub1 < my_supr
properties (Constant)
foo = 1;
baz = 2;
end
end
classdef my_sub2 < my_supr
properties (Constant)
foo = 7;
baz = 9;
end
end
Now this mostly works and my_sub1.foo returns 1, and my_sub2.foo returns 7. What I'd like to do is structure the hierarchy in a way that would let me define:
classdef my_sub3 < my_sub1
properties (Constant)
foo = 11; %This does not work
end
end
The intent here is to define the new set of constants, but only override some of them. Is there some magic combination of property attributes that would let me do this?

Accepted Answer

Benjamin Kraus
Benjamin Kraus on 4 Jun 2025
Edited: Benjamin Kraus on 4 Jun 2025
Based on this statement:
What I really want is:
#define foo (1)
#if MY_SW_VERSION > 1
#define baz(2)
#else
#define baz(1)
#endif
I think what you are really looking for is a singleton pattern.
There are several mechanisms for implementing a singleton in MATLAB, but here's my favorite somewhat unintuitive method.
classdef Registry < handle
properties (Constant)
% When the "Registry" object is first initialized, it populates the
% ConstantsRegistry object with an object. Because
% ConstantsRegistry is a handle-class object, that same object is
% shared by all instances of "Registry".
ConstantsRegistry (1,1) ConstantsRegistry = ConstantsRegistry
end
end
classdef ConstantsRegistry < handle
properties
Constants
end
end
classdef Constants
properties (Constant)
Foo = 1;
end
end
classdef AlternateConstants
properties (Constant)
Foo = 2;
end
end
Registry.ConstantsRegistry.Constants.Foo % Returns 1
Registry.ConstantsRegistry.Constants = AlternateConstants;
Registry.ConstantsRegistry.Constants.Foo % Returns 2
Alternatively
A much more common and intuitive version of a singleton in MATLAB:
classdef Registry < handle
properties
Constants
end
methods (Access=private)
% Restrict access to the constructor so that only one object can be
% constructed.
function obj = Registry()
obj.Constants = Constants;
end
end
methods (Static)
function obj = getInstance()
persistent instance
if isempty(instance) || ~isvalid(instance)
instance = Registry();
end
obj = instance;
end
end
end
classdef Constants
properties (Constant)
Foo = 1;
end
end
classdef AlternateConstants
properties (Constant)
Foo = 2;
end
end
Registry.getInstance().Constants.Foo % Returns 1
r = Registry.getInstance();
r.Constants = AlternateConstants;
Registry.getInstance().Constants.Foo % Returns 2

More Answers (3)

Steven Lord
Steven Lord on 4 Jun 2025
Doing so would violate the Liskov substitution principle.
As a contrived example, let's say you had a Shape class that had an abstract and constant numSides property.
classdef Shape
properties(Abstract, Constant)
numSides
end
end
I could define a Square class that isa Shape with numSides equal to 4. This makes sense by the standard definition of a square shape:
classdef Square < Shape
properties(Constant)
numSides = 4;
end
end
Now if I were to define a Mysquare class that isa Square, an instance of Mysquare ought to be substitutable / usable anywhere I used an instance of Square. That's what the Liskov substitution principle says (very generally.)
classdef Mysquare < Square
properties(Constant)
numSides = 5;
end
end
A Square must have 4 sides.
A Mysquare must have 5 sides. [So we could have called this class the Pentagon class.]
So a Mysquare cannot be a Square.
But a Mysquare isa Square.
That's a contradiction.
For your real system of classes, how would you avoid this violation of Liskov?
  1 Comment
John
John on 4 Jun 2025
Edited: John on 4 Jun 2025
Hmm. It's a reasonable point. But let me backtrack. To be honest, I'm not trying to establish a hierarchy of objects with wider semantic meaning. I just want a container for some constants. Matlab doesn't really have anything like headers so we make do. What I really want is:
#define foo (1)
#if MY_SW_VERSION > 1
#define baz(2)
#else
#define baz(1)
#endif
With an abstract superclass the inheritance doesn't really get me much. It satisfies an isa relationship, but that's not really how this would be used.

Sign in to comment.


Andrew Ouellette
Andrew Ouellette on 4 Jun 2025
You can approximate this behavior with Dependent properties and getter methods.
classdef (Abstract) my_supr
properties (Dependent, SetAccess=private)
foo
end
methods
function foo = get.foo(this)
foo = this.getfoo();
end
end
methods (Abstract,Static,Access=protected)
foo = getfoo()
end
end
classdef my_sub1 < my_supr
methods (Static,Access=protected)
function foo = getfoo()
foo = 1;
end
end
end
classdef my_sub2 < my_supr
methods (Static,Access=protected)
function foo = getfoo()
foo = 7;
end
end
end
classdef my_sub3 < my_sub1
methods (Static,Access=protected)
function foo = getfoo()
foo = 11;
end
end
end
  1 Comment
John
John on 4 Jun 2025
Thanks for your suggestion. Unfortunately, I don't think this would be particularly effective as there would be significant calling overhead in invoking all the get-methods for the dependent parameters. In many applications it probably won't matter, but I have some 'inner loop' functions that need access to the constants.

Sign in to comment.


Matt J
Matt J on 4 Jun 2025
Edited: Matt J on 4 Jun 2025
Something like this, perhaps?
classdef myclass
methods (Static)
function valid=approveProps(classname)
%props=eval("?"+classname); props=props.PropertyList;
props=matlab.metadata.Class.fromName(classname).PropertyList;
names={props.Name}; names=names([props.Constant] & ~[props.Hidden]);
valid=all(ismember(names,{'foo','bar','x','y','z'})); %approved list
if ~valid
disp("Illegal constant Property in class "+classname);
end
end
end
end
and then in the subclasses,
classdef mysubclass1<myclass
properties (Constant)
foo=1;bar=3; z=5;
end
properties (Constant, Hidden)
arePropsValid=myclass.approveProps(mfilename);
end
end
classdef mysubclass2<myclass
properties (Constant)
foo=1;
Q=1; %Unapproved property -- will throw error
end
properties (Constant, Hidden)
arePropsValid=myclass.approveProps(mfilename);
end
end
  5 Comments
Paul
Paul on 4 Jun 2025
Edited: Paul on 4 Jun 2025
Is there anything inherently problematic with using eval here?
"if you have an instance of the class"
Does the properties block not have the instance of the class on which the properties are being set? Or is that not the case because the instance isn't fully constructed (so to speak) yet? In either case, the "if you have" is throwing me off. It sounds like there might be some uses where the class instance is available and other uses where it's not.
If metaclass(classname) were allowed then
metaclass("myobject")
would be ambiguous. Should that return the Class of the myobject class, or the Class of the string class, of which "myobject" is an instance, as it does currently.
Matt J
Matt J on 5 Jun 2025
@Paul Yes, that's a good point. Although, I still wonder if it would have been more streamlined if ? had been the version that operates on a given object,
?obj
metaclass(classname)

Sign in to comment.

Categories

Find more on Class File Organization in Help Center and File Exchange

Products


Release

R2024b

Community Treasure Hunt

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

Start Hunting!