Is it possible in one line to get a class value from a function and modify it? - matlab

If I have a class
classdef foo
properties
a = 0;
end
methods
function obj foo(obj)
obj.a = 5;
end
end
end
And a function
function result = GetFoo()
result = foo();
end
At the command interpreter:
>> x = GetFoo()
x =
foo
Properties:
a: 5
Methods
>> x.a = 10
x =
foo
Properties:
a: 10
Methods
this yields an instance of foo and the value 'a' can be assigned. However, doing the same in one step:
>> GetFoo().a = 10
GetFoo =
a: [1x1 struct]
This creates a new structure called GetFoo that overrides the class and gives it a member called 'a'. Rather than the code getting the result of GetFoo() (the class instance) and settings its property 'a' = 10, it does this instead. I can see that it is likely a hangover from the ability to create weakly typed structures on the fly and the code having to be backward compatible It also seems to be related to the fact that MATLAB has no concept of a pointer so every input/output argument is a deep copy and that the above even if it would work would be setting the value of a copy of the value GetFoo() is using to source its return object, then throwing it away.
Nonetheless the goal really is to be able to do all the work I need without creating and requiring to clear temporary variables. The intent is code maintainability as much as cosmetic style.

You're mixing together quite a few different issues/complaints in your question, but I suspect what you're looking for is a handle class. Inherit your class from handle (i.e. write classdef foo < handle, and your class will have what is basically pass-by-reference behavior. You're right that MATLAB doesn't use pointers, but with handle classes it does have references.
Separately, it's not possible in MATLAB to index in to the output of a function (i.e. to write GetFoo.a or GetFoo().a - you do need a temporary variable for that, whether or not it returns a value or handle class.
Note that in your example above, the result of the GetFoo().a = 10 is not an instance of foo with the property a equal to 10 - it is a structure with a field a equal to 10. Type class(GetFoo), and you'll see it's a struct, not a foo.

This is really ugly, but is just to raise the glove that was thrown about doing it in one line. :-)
First of all, I'll modify a bit the class so you'll see that the constructor is called:
classdef foo
properties
a = 0;
end;
methods
function obj = foo()
obj.a = 5;
display('foo!');
end;
end;
end
And the one-liner, ran in Command Window:
>> subsasgn(GetFoo(), struct('type', '.', 'subs', 'a'), 10);
foo!

Related

Property initialization in MATLAB

In MATLAB there are two ways to initialize its properties. Either directly in the properties:
classdef A
properties
foo = 'bar';
end
end
or by explicitly defining a constructor:
classdef B
properties
foo;
end
methods this = B()
this.foo = 'bar';
end
end
Which one is the more preferable way?
(I am asking because there is a similar case in C++ where the preferred way is to initialize the member variables with a colon after the constructor rather than assigning variables within the constructor).
In most cases, the two methods behave the same, and the choice is just a preference depending on which you find clearer/easier to maintain etc.
But they are not the same, and there are cases where you will get yourself in trouble if you aren't aware of the differences.
The essential difference is that properties that are initialised in the constructor are initialised separately each time an object is constructed, whereas properties that are initialised in the properties block with a default value are initialised once, when the class definition is first read. The default value in a properties block is the default value of the class, not of the object; and (using reflection) you can query that default value even if no instance of the class has yet been instantiated.
In most cases, this makes no difference - but when the initial value is a handle object, or the output of a non-determinate function it does. So consider the following two classes:
classdef A
properties
foo
end
methods
function obj = A
obj.foo = containers.Map;
end
end
end
classdef B
properties
foo = containers.Map
end
end
Note that containers.Map is a handle class.
In class A, every time you create a new instance of A you get a new/different containers.Map for its foo. In B, every instance of B gets the same containers.Map for its foo, as the property is initialised only once, the first time the class definition is read. So if you modify foo for any object of class B, that change is propagated to all other instances of class B, as you can see:
>> a1 = A; a2 = A; a1.foo('greeting') = 'hello'; a2.foo('greeting') = 'bonjour';
>> a1.foo('greeting'), a2.foo('greeting')
ans =
'hello'
ans =
'bonjour'
>> b1 = B; b2 = B; b1.foo('greeting') = 'hello'; b2.foo('greeting') = 'bonjour';
>> b1.foo('greeting'), b2.foo('greeting')
ans =
'bonjour'
ans =
'bonjour'
>> % Note that b1.foo has changed as a result of setting b2.foo
This point about handle classes as default values often trips people up; but the behaviour is not specific to handle classes. For example, consider the following variation:
classdef A
properties
foo
end
methods
function obj = A
obj.foo = datetime('now');
end
end
end
classdef B
properties
foo = datetime('now')
end
end
Here A will store the creation time of each object, whereas B will store the time at which the class was first initialised, for all objects, no matter when they were created.
In case you find this behaviour confusing, see https://undocumentedmatlab.com/blog/handle-object-as-default-class-property-value, and particularly the comment thread underneath that article, for a discussion of the issue, and an explanation for the reasons MATLAB is designed in this way.
Edit: Great follow up question in the comments, regarding the behaviour of clear and its relation to this issue.
Using the second implementation of the classes above (with datetime), look at the following:
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:30'
ans =
'01-Sep-2018 18:59:30'
>> clear variables
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:48'
ans =
'01-Sep-2018 18:59:30'
>> clear classes
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:57'
ans =
'01-Sep-2018 18:59:57'
So we first of all create an A and a B, and display their foos, and they both show the same time. Then we wait a little while, do clear variables, and we do it again. Note that the foo from A is the new time, and the foo from B is still the same as before. Finally we wait a little more time, we do clear classes, and we do it again. This time both A and B have the new time.
Why? Because clear variables merely removes references to the variables from the workspace. The class definition of B is not cleared, so when we create another B, it still uses the value from when the class definition was first read. clear classes, by contrast, also removes the class definition, so when we later construct a new B, it gets that time, as the class definition is then reread. All this is irrelevant to A, as foo is just given a value at construction time.
Note that clear classes clears all class definitions: you can clear the definition of only class B using clear B.
It is on your choice except for some cases.
Let me mention when we use the colon in Constructor function inC++:
1- Calling base class constructors
2- Initializing member variables before the body of the constructor executes.
No.#1 can be also used in the body but we should use the colon in No.#2 when the member is const.
BUT
But here is Matlab, with its own language syntax and structure.
Use which one do your job.
But here in Matlab when you want to define Constant properties you MUST define it in properties part and you can't do it in initializer/constructor function.
classdef NamedConst
properties (Constant)
R = pi/180; % Can't define it in constructor body, because it is `Constant properties`
end
%class body
end

Static properties in Matlab [duplicate]

Is there a way to define static member variables in MATLAB classes?
This doesn't work:
classdef A
properties ( Static )
m = 0;
end
end
It suggests to use keyword "Constant" instead of "Static", the constant properties cannot be modified. I want a variable common to all objects of class A and I want to be able to modify that variable in methods of class A.
So what I need is a private static member variable. Is there a way to obtain it in MATLAB?
Found out that a workaround can be done using persistent variables in static member functions.
In this case you should inherit all your classes from a base class like the following.
classdef object < handle
properties ( GetAccess = 'public', SetAccess = 'private' )
id
end
methods ( Access = 'protected' )
function obj = object()
obj.id = object.increment();
end
end
methods ( Static, Access = 'private' )
function result = increment()
persistent stamp;
if isempty( stamp )
stamp = 0;
end
stamp = stamp + uint32(1);
result = stamp;
end
end
end
You can not, it is by design. You should use a persistent variable (technique from the MATLAB as 1980 applied in year 2011)!
For completeness I should mention that actually there is as of 2010b an undocumented and probably not longer supported static property modifier.
For background see here the answer of Dave Foti, MATLAB OO group manager:
In MATLAB, classes can define Constant
properties, but not "static"
properties in the sense of other
languages like C++. There were beta
releases that experimented with
"Static" properties and the
undocumented attribute remains from
then. However, the Static attribute is
undocumented, should not be used, and
will likely be removed in a future
MATLAB release. R2008a implements it
as a synonym for Constant and provides
no additional functionality beyond
the documented behavior of Constant
properties.
Constant properties may not be changed
from the initial value specified in
the property declaration. There are a
couple of reasons why MATLAB works
the way it does. First, MATLAB has
longstanding rules that variables
always take precedent over the names
of functions and classes and that
assignment statements introduce a
variable if one doesn't already exist.
Thus, any expression of the form "A.B
= C" will introduce a new variable A that is a struct array containing a
field B whose value is C. If "A.B = C"
could refer to a static property of
class A, then class A would take
precedent over variable A and this
would be a very significant
incompatibility with prior releases
of MATLAB. It would mean that an
m-file containing the assignment
statement "A.B = C" could have its
meaning changed by the introduction
of a class named A somewhere on the
MATLAB path. MATLAB programmers have
always been able to rely on assignment
statements introducing variables that
shadow any other use of the same name.
Second, we have observed that static
data is rarely used in other classes
except as private data within the
class or as public constants. For
example, a survey of several Java
class libraries found that all public
static fields were also final. In
MATLAB, Constant properties can be
used like "public final static"
fields in Java. For data internal to a
class, MATLAB already has persistent
variables that can be created inside
of private or protected methods or
local functions privately used by a
class. There are also good reasons to
avoid static data in MATLAB where
possible. If a class has static data,
it can be difficult to use the same
class in multiple applications
because the static data can be a
source of conflicts among
applications. In some other languages,
this is less of an issue because
different applications are separately
compiled into executables running in
different processes with different
copies of class static data. In
MATLAB, frequently many different
applications may be running in the
same process and environment with a
single copy of each class.
Here's a direct way to create a static property in Matlab. The only difference between this implementation and a hypothetical (but impossible; see Mikhail's answer) true static property is the syntax for setting the member variable.
classdef StaticVarClass
methods (Static = true)
function val = staticVar(newval)
persistent currentval;
if nargin >= 1
currentval = newval;
end
val = currentval;
end
end
end
Now the static property staticVar can be read via:
StaticVarClass.staticVar
...and be set via:
StaticVarClass.staticVar(newval);
So, for instance, this is the expected output from a test of this functionality:
>> StaticVarClass.staticVar
ans =
[]
>> StaticVarClass.staticVar('foobar')
ans =
foobar
>> StaticVarClass.staticVar
ans =
foobar
>>
This approach works just as well for private static properties like you requested, but the demo code is a little longer. Note that this is not a handle class (though it would work perfectly well on a handle class as well).
classdef StaticVarClass
methods (Access = private, Static = true)
function val = staticVar(newval)
persistent currentval;
if nargin >= 1
currentval = newval;
end
val = currentval;
end
end
methods
function this = setStatic(this, newval)
StaticVarClass.staticVar(newval);
end
function v = getStatic(this)
v = StaticVarClass.staticVar;
end
end
end
...and the test:
>> x = StaticVarClass
x =
StaticVarClass with no properties.
Methods
>> x.getStatic
ans =
[]
>> x.setStatic('foobar')
ans =
StaticVarClass with no properties.
Methods
>> x.getStatic
ans =
foobar
>>
(just to inform)
there is (another?) way to create static-like data in matlab
suppose that you have a "handle" class which its name is "car"
if you want the car class to have static data, you could construct another handle class and use it in car class throw composition, the latter class works as a static data for car class
classdef car<handle
properties
static_data:STATIC_DATA_HOLDER;
end
end
classdef STATIC_DATA_HOLDER<handle
properties
data
end
end
this way when you create first instance of a car class, an instance of STATIC_DATA_HOLDER will be created and when you create second instance of car class it uses previously created STATIC_DATA_HOLDER class.
these code tested with "MATLAB 2013b"
Another workaround to get something like static properties is to use the fact that initialisation code for member variables is only executed once when the class file is loaded. That means, if you have a definition like
classdef foo
properties
stuff = some_function()
end
end
then some_function is invoked only once, and if it returns an object of class type, this will be shared by all instances. I've added a sample implementation that shows how that can be used:
classdef ClassWithStaticMembers
properties
classvars = StaticVarContainer('foo', 0, 'bar', 2);
othervar
end
methods
function obj=ClassWithStaticMembers(var)
obj.othervar = var;
end
end
end
classdef StaticVarContainer < dynamicprops
methods
function obj=StaticVarContainer(varargin)
for i=1:2:numel(varargin)
obj.addprop(varargin{i});
obj.(varargin{i}) = varargin{i+1};
end
end
end
end
If you run this sample code
obj1 = ClassWithStaticMembers(3);
obj2 = ClassWithStaticMembers(5);
obj1.classvars.foo = [2,3];
obj1.othervar
obj1.classvars
obj2.othervar
obj2.classvars
you'll see, that classvars is indeed shared. I think this solution is much nicer than using persistent variables in functions, since you can reuse the StaticVarContainer as often as you want, it's easier to use, and furthermore, you directly see the initialisation of the static variables in the properties section.
To get the result, that is desired in the OP's question (i.e. implementing an object counter) the shared property can be made Constant, so that it can be referenced without an instance at hand:
classdef ClassWithCounter
properties (Constant)
static = StaticVarContainer('counter', 0);
end
methods
function obj=ClassWithCounter()
obj.static.counter = obj.static.counter + 1;
end
end
end
clear all
obj1 = ClassWithCounter();
obj2 = ClassWithCounter();
obj3 = ClassWithCounter();
ClassWithCounter.static.counter
Note, that the Constant attribute only means that, e.g. obj1.static cannot be changed, but it does not affect obj1.static.counter which is not constant, and can be set to heart's desire.

When can I pass a function handle?

I have a function for cached evaluation. As one of the arguments, it takes a function handle. Under some circumstances, the function handle is unaccessible, and I don't quite understand why. The example below shows what got me stumped:
>> A.a = #plus; feval(#A.a, 1, 1)
ans =
2
>> clear A
>> A.a.a = #plus; feval(#A.a.a, 1, 1)
Error using feval
Undefined function 'A.a.a' for input arguments of type 'double'.
So, if I have a function handle stored as a structure member, I can pass it along fine if it's one level deep, but not if it's two levels deep. In my real use case, I have a structure D that holds many (117) instances of various classes, so I actually have stct.obj.meth, where stct is a structure, obj is a class instance/object, and meth is a method. Passing #stct.obj.meth fails, but if I assign A = stct.obj, then passing #A.meth succeeds.
Under what conditions can I pass a function handle as an argument, so that it's still accessible down the stack?
Edit: Although in the use case above, I could simply remove the # because #plus is already a function handle. However, consider the situation here:
>> type cltest.m
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
end
end
>> A.a = cltest();
>> feval(#A.a.mymeth, 1, 1)
Error using feval
Undefined function 'A.a.mymeth' for input arguments of type 'double'.
>> b = A.a;
>> feval(#b.mymeth, 1, 1)
ans =
2
In this case, I need the # before A.a.mymeth...
Introducing classes was a big deal for MATLAB. So big, in fact, that they still do not work properly today. Your example shows that structure access and class method access conflict, because they had to overload the the meaning of dot '.' and didn't get it to work seamlessly. It all more or less works fine when you are calling class methods explicitly by their name on the MATLAB console, e.g. in your example >> A.a.mymeth(1,1). But when you have any type of indirection, it soon breaks.
You tried getting the function handle by >> #A.a.mymeth, which MATLAB cannot make sense of, probably because it gets confused by the mixed structure/class thing. Trying to work around using str2func doesn't work either. It works, again, only for explicit name access, as shown here. It breaks for your example, e.g. >> str2func('b.mymeth'). It does not even work inside the class. Try other indirections and watch them fail.
Additionally, MATLAB does not like giving you a class method's handles. There's no function for it. There's no way to get all function handles in one go, or even dynamically by a name string.
I see three options here. First, try changing your program, if possible. Do these functions need to sit in a classdef?
Second, follow your or nispio's workaround. They both create a temporary variable to hold a reference to the class instance in order to create a non-mixed access to its member methods. The problem is, they both require explicitly naming the function. You have to explicitly put this code for every function involved. No way to abstract that out.
Third, cheat by giving out your class' method handles from the inside. You can give them out in a structure.
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
function hs = funhandles(self)
hs = struct('mymeth', #self.mymeth, ...
'mymeth2', #self.mymeth2);
end
end
end
You can then access the handles by name, even dynamically.
>> A.a = cltest;
>> feval(A.a.funhandles.mymeth, 1, 1);
>> feval(A.a.funhandles.('mymeth'), 1, 1)
ans =
2
But be careful, by using this you can access Access=private methods from outside.
Try this:
feval(#(varargin)A.a.mymeth(varargin{:}),1,1);
It is a little kludgy, but it should work.
EDIT:
The way it works is by creating an Anonymous Function that takes a variable number of arguments, and dumps those arguments into the method A.a.mymeth(). So you are not actually passing a pointer to the function A.a.mymeth, you are passing a pointer to a function that calls A.a.mymeth.
An alternative way of achieving the same thing without using varargin would be:
feval(#(x,y)A.a.mymeth(x,y),1,1);
This creates an anonymous function that accepts two arguments, and passes them along to A.a.mymeth.
<speculation> I think that it must be inherent in the way that the unary function handle operator # works. The Matlab parser probably looks at #token and decides whether token is a valid function. In the case of a.mymeth it is smart enough to decide that mymeth is a member of a, and then return the appropriate handle. However, when it sees A.a.mymeth it may discover that A is not a class, nor does A have a member named a.mymeth and therefore no valid function is found. This seems to be supported by the fact that this works:
A.a.a = #plus; feval(A.a.a,1,1)
and this doesn't:
A.a.a = #plus; feval(#A.a.a,1,1)
</speculation>
You can get around it by introducing a separate function that corrects what # operator is not doing:
function h=g(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now for your example:
>> feval(g(#A.a.mymeth), 1, 1)
ans =
2
>> feval(g(#b.mymeth), 1, 1)
ans =
2
I think this will have the smallest impact on your code. You can make it a bit more elegant but less robust and/or readable. The uplus method is not defined for function_handle class so you can create uplus.m in folder #function_handle somewhere in your path with this content:
function h=uplus(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now you just need to use +# instead of #. For your examples:
>> feval(+#A.a.mymeth, 1, 1)
ans =
2
>> feval(+#b.mymeth, 1, 1)
ans =
2

Sub-struct with dependent fields

In Matlab, I would like a data structure that looks like so:
DataStruct
.model
.Q
.Qchol
.
.
.system
.
.
The structure may well be a class, although I don't really need all the other functionality that goes with oop.
But I require
If Q is assigned something, then automatically Qchol = cholcov(Q).
If Qchol is assigned something, then automatically Q = Qchol' * Qchol.
Meanwhile, both Q and Qchol are stored for fast read-access
And Q and Qchol are writable through simple assignment, e.g.: DS1.mod.Q = value
I know I can make model a class, and have set/get methods for Q and Qchol. However, this really seems like an overkill for just two matrices (plus maybe some more fields). Also Matlab warns me that I should not access other properties during in a set method.
So: What is the best way to have such data structures, preferably without warnings?
You basically want assignment (DS1.mod.Q = value) to have side-effects, which inevitably implies a setter, and hence a class. You should either drop this requirement, or write a class.
If you wish to avoid definition of properties in the class declaration, you could use Dynamic Properties, which allows you to add properties at runtime (although with some telltale syntax addprop()).
EDIT
Patric, the problem goes deeper then just M-lint. Consider the following class:
classdef cantInstantiateMe < handle
properties
x
minus_x
end
methods
function obj = cantInstantiateMe(x)
obj.x = x; % <-- this calls set.x(), which calls set.minus_x(), which calls set.x(), ...
obj.minus_x = -x;
end
function set.x(obj, value)
obj.x = value;
obj.minus_x = -value; % <-- this gives an M-Lint warning
end
function set.minus_x(obj, value)
obj.minus_x = value;
obj.x = -value;
end
end
end
This class cannot be instantiated, because each setter calls the other setter (this is not Matlab-specific). Trying to instantiate on my machine gives:
??? Maximum recursion limit of 500 reached. Use set(0,'RecursionLimit',N)
to change the limit. Be aware that exceeding your available stack space can
crash MATLAB and/or your computer.
At this point I think you have two options:
Make either Q or Qchol a dependent property. This will come at the cost of re-calculating the dependent property each time you read-access it.
Use some private shadow properties e.g. shadow_Q and shadow_Qchol which will be set when the setter for the public property is called, and returned when their getter is called. Similar to:
function set.x(obj, value)
obj.shadow_x = value;
obj.shadow_minus_x = -value;
end
function value = get.x(obj)
value = obj.shadow_x;
end
Note the I did not test this properly, so I don't know all implications in Matlab. In other languages I'm familiar with, this should work fine.
Regarding the warning - my approach is that it is safe to disable the warning, as long as you really know what you are doing.
As suggested by #bavaza, one way to implement this is to use a dependent property with corresponding shadow private properties.
Below is the code implementing the inner data structure (inspired by this post). You need to use composition to make an instance of this class a property of the outer object:
classdef Model < handle
properties (Dependent)
Q
Qchol
end
properties (Access = private)
Q_
Qchol_
end
methods
function obj = Model()
end
function val = get.Q(obj)
val = obj.Q_;
end
function val = get.Qchol(obj)
val = obj.Qchol_;
end
function set.Q(obj, val)
obj.Q_ = val;
obj.Qchol_ = cholcov(val);
end
function set.Qchol(obj, val)
obj.Qchol_ = val;
obj.Q_ = val'*val;
end
end
end
Setting one value using the exposed dependent properties affects both underlying variables:
>> m = Model
m =
Model with properties:
Q: []
Qchol: []
>> m.Qchol = rand(3)
m =
Model with properties:
Q: [3x3 double]
Qchol: [3x3 double]

How to obtain static member variables in MATLAB classes?

Is there a way to define static member variables in MATLAB classes?
This doesn't work:
classdef A
properties ( Static )
m = 0;
end
end
It suggests to use keyword "Constant" instead of "Static", the constant properties cannot be modified. I want a variable common to all objects of class A and I want to be able to modify that variable in methods of class A.
So what I need is a private static member variable. Is there a way to obtain it in MATLAB?
Found out that a workaround can be done using persistent variables in static member functions.
In this case you should inherit all your classes from a base class like the following.
classdef object < handle
properties ( GetAccess = 'public', SetAccess = 'private' )
id
end
methods ( Access = 'protected' )
function obj = object()
obj.id = object.increment();
end
end
methods ( Static, Access = 'private' )
function result = increment()
persistent stamp;
if isempty( stamp )
stamp = 0;
end
stamp = stamp + uint32(1);
result = stamp;
end
end
end
You can not, it is by design. You should use a persistent variable (technique from the MATLAB as 1980 applied in year 2011)!
For completeness I should mention that actually there is as of 2010b an undocumented and probably not longer supported static property modifier.
For background see here the answer of Dave Foti, MATLAB OO group manager:
In MATLAB, classes can define Constant
properties, but not "static"
properties in the sense of other
languages like C++. There were beta
releases that experimented with
"Static" properties and the
undocumented attribute remains from
then. However, the Static attribute is
undocumented, should not be used, and
will likely be removed in a future
MATLAB release. R2008a implements it
as a synonym for Constant and provides
no additional functionality beyond
the documented behavior of Constant
properties.
Constant properties may not be changed
from the initial value specified in
the property declaration. There are a
couple of reasons why MATLAB works
the way it does. First, MATLAB has
longstanding rules that variables
always take precedent over the names
of functions and classes and that
assignment statements introduce a
variable if one doesn't already exist.
Thus, any expression of the form "A.B
= C" will introduce a new variable A that is a struct array containing a
field B whose value is C. If "A.B = C"
could refer to a static property of
class A, then class A would take
precedent over variable A and this
would be a very significant
incompatibility with prior releases
of MATLAB. It would mean that an
m-file containing the assignment
statement "A.B = C" could have its
meaning changed by the introduction
of a class named A somewhere on the
MATLAB path. MATLAB programmers have
always been able to rely on assignment
statements introducing variables that
shadow any other use of the same name.
Second, we have observed that static
data is rarely used in other classes
except as private data within the
class or as public constants. For
example, a survey of several Java
class libraries found that all public
static fields were also final. In
MATLAB, Constant properties can be
used like "public final static"
fields in Java. For data internal to a
class, MATLAB already has persistent
variables that can be created inside
of private or protected methods or
local functions privately used by a
class. There are also good reasons to
avoid static data in MATLAB where
possible. If a class has static data,
it can be difficult to use the same
class in multiple applications
because the static data can be a
source of conflicts among
applications. In some other languages,
this is less of an issue because
different applications are separately
compiled into executables running in
different processes with different
copies of class static data. In
MATLAB, frequently many different
applications may be running in the
same process and environment with a
single copy of each class.
Here's a direct way to create a static property in Matlab. The only difference between this implementation and a hypothetical (but impossible; see Mikhail's answer) true static property is the syntax for setting the member variable.
classdef StaticVarClass
methods (Static = true)
function val = staticVar(newval)
persistent currentval;
if nargin >= 1
currentval = newval;
end
val = currentval;
end
end
end
Now the static property staticVar can be read via:
StaticVarClass.staticVar
...and be set via:
StaticVarClass.staticVar(newval);
So, for instance, this is the expected output from a test of this functionality:
>> StaticVarClass.staticVar
ans =
[]
>> StaticVarClass.staticVar('foobar')
ans =
foobar
>> StaticVarClass.staticVar
ans =
foobar
>>
This approach works just as well for private static properties like you requested, but the demo code is a little longer. Note that this is not a handle class (though it would work perfectly well on a handle class as well).
classdef StaticVarClass
methods (Access = private, Static = true)
function val = staticVar(newval)
persistent currentval;
if nargin >= 1
currentval = newval;
end
val = currentval;
end
end
methods
function this = setStatic(this, newval)
StaticVarClass.staticVar(newval);
end
function v = getStatic(this)
v = StaticVarClass.staticVar;
end
end
end
...and the test:
>> x = StaticVarClass
x =
StaticVarClass with no properties.
Methods
>> x.getStatic
ans =
[]
>> x.setStatic('foobar')
ans =
StaticVarClass with no properties.
Methods
>> x.getStatic
ans =
foobar
>>
(just to inform)
there is (another?) way to create static-like data in matlab
suppose that you have a "handle" class which its name is "car"
if you want the car class to have static data, you could construct another handle class and use it in car class throw composition, the latter class works as a static data for car class
classdef car<handle
properties
static_data:STATIC_DATA_HOLDER;
end
end
classdef STATIC_DATA_HOLDER<handle
properties
data
end
end
this way when you create first instance of a car class, an instance of STATIC_DATA_HOLDER will be created and when you create second instance of car class it uses previously created STATIC_DATA_HOLDER class.
these code tested with "MATLAB 2013b"
Another workaround to get something like static properties is to use the fact that initialisation code for member variables is only executed once when the class file is loaded. That means, if you have a definition like
classdef foo
properties
stuff = some_function()
end
end
then some_function is invoked only once, and if it returns an object of class type, this will be shared by all instances. I've added a sample implementation that shows how that can be used:
classdef ClassWithStaticMembers
properties
classvars = StaticVarContainer('foo', 0, 'bar', 2);
othervar
end
methods
function obj=ClassWithStaticMembers(var)
obj.othervar = var;
end
end
end
classdef StaticVarContainer < dynamicprops
methods
function obj=StaticVarContainer(varargin)
for i=1:2:numel(varargin)
obj.addprop(varargin{i});
obj.(varargin{i}) = varargin{i+1};
end
end
end
end
If you run this sample code
obj1 = ClassWithStaticMembers(3);
obj2 = ClassWithStaticMembers(5);
obj1.classvars.foo = [2,3];
obj1.othervar
obj1.classvars
obj2.othervar
obj2.classvars
you'll see, that classvars is indeed shared. I think this solution is much nicer than using persistent variables in functions, since you can reuse the StaticVarContainer as often as you want, it's easier to use, and furthermore, you directly see the initialisation of the static variables in the properties section.
To get the result, that is desired in the OP's question (i.e. implementing an object counter) the shared property can be made Constant, so that it can be referenced without an instance at hand:
classdef ClassWithCounter
properties (Constant)
static = StaticVarContainer('counter', 0);
end
methods
function obj=ClassWithCounter()
obj.static.counter = obj.static.counter + 1;
end
end
end
clear all
obj1 = ClassWithCounter();
obj2 = ClassWithCounter();
obj3 = ClassWithCounter();
ClassWithCounter.static.counter
Note, that the Constant attribute only means that, e.g. obj1.static cannot be changed, but it does not affect obj1.static.counter which is not constant, and can be set to heart's desire.