Matlab: How do I call a function which I have defined within a class? - matlab

I'm trying to learn how to use classes in Matlab, having never used them in any language before, so apologies if this is a bit basic.
I have defined a class called car, with the properties of colour, type, serial number and speed, with a function to change the speed.
classdef car <handle
properties
colour
type
speed
end
properties (SetAccess = private)
SerialNumber
end
methods
function faster(obj, v)
obj.speed = obj.speed + v;
end
end
end
In another script I can type
car.colour = "red", and when I disp(car), the class has the property colour with label "red". When I call faster(100) however, instead of setting car.speed=100, it throws the error
Check for missing argument or incorrect argument data type in call to function 'faster'.
I built the class and method using the same sort of code structure as in this question:
https://www.mathworks.com/matlabcentral/answers/395472-how-to-call-a-method-from-a-class-called-a-within-another-method-from-a
where the user seemed to not have the issue I do. I'm not sure where I'm going wrong - my function seems like it should work. Can anybody point me in the right direction?

You need to call the function on the class
myCar = car();
myCar.faster( 10 ); % equivalent to 'faster( myCar, 10 )'
If you hadn't specified the < handle type, you would also need to assign it back to the class, i.e.
myCar = myCar.faster( 10 );
But you don't need this with a handle class.

Related

Get Class of an Object From Superclass in Matlab

Constant properties are static properties(belongs to classes, not instances) in Matlab, like many other OOP languages. And natural way to access them is ClassName.PropName as in Matlab documentation.
However, I couldn't find a way to do ClassName.PropName from a superclass, in a scenario like this:
classdef (Abstract) Superclass < handle
properties(Dependent)
dependentProperty
end
properties (Abstract, Constant)
constantProperty
end
methods
function result = get.dependentProperty(obj)
c = class(obj); % Here I have to get class of obj
result = length(c.constantProperty); % to use here as `ClassName.PropName`
end
end
end
classdef Subclass < Superclass
properties (Constant)
constantProperty = [cellstr('a'); cellstr('b')];
end
end
so that following commands results following outputs this:(expected output)
>> subclassInstance = Subclass()
subclassInstance =
Subclass with properties:
constantProperty: {2×1 cell}
dependentProperty: 2
>> subclassInstance.dependentProperty
ans =
2
>>
But instead, I get following this:(actual output)
>> subclassInstance = Subclass()
subclassInstance =
Subclass with properties:
constantProperty: {2×1 cell}
>> subclassInstance.dependentProperty
Struct contents reference from a non-struct array object.
Error in Superclass/get.dependentProperty (line 13)
result = length(c.constantProperty);
>>
Also tried: c = metaclass(obj) which gives "No appropriate method, property, or field 'constantProperty' for
class 'meta.class'."
Question: Is there any way to obtain class of an object from superclass, to be able write a statement like ClassName.PropName?
EDIT:
I know I can reach from object reference like this:
function result = get.dependentProperty(obj)
result = length(obj.constantProperty);
end
But this is not what I want as it makes reader to think constantProperty is an instance property. Also this is not documented in Matlab, instead documentation says ClassName.PropName and this makes me think that there must be a way.
The right way to do this in matlab is through the instance, as per the part of my previous answer you have now incorporated in your question. This is because matlab's object-orientation model is "instance" based.
The constant property is an instance property; it just happens to be the same (i.e. constant) in all instances. Presumably, this is why it's called "constant", not "static": it does not refer to a single static item in memory, like in c; instead every instance is instantiated with that same constant value.
You gain nothing by going out of your way to call it via a "class reference" (no such thing exists btw; unlike python and julia, class prototypes are not objects that can be referred to, nor do they have a type themselves).
However, if you insist, there does happen to be a way to do this using metaclasses, since a constant property set from within the constructor will have a default value named in its metaclass profile
subclassInstance = Subclass();
m = metaclass(subclassInstance);
mp = findobj (m.PropertyList, 'Name', 'constantProperty');
mp.DefaultValue
Also, to address why class(subclassInstance).constantProperty doesn't work, this is simply because the result of class(subclassInstance) is a string (whose value happens to be the classname), not a "reference" to a class (like I said, such a thing doesn't exist in matlab).
However, if you wanted to, obviously you could use such a classname string within an eval statement, to evaluate it as if you were typing it directly in the terminal to access the constant property. So this is another way of achieving what you're after:
eval([class(subclassInstance) '.constantProperty'])
but in theory eval statements should generally be avoided unless there's no alternative.
Short note:
in Java this is possible by this.getClass()
In java this is called reflection, and it's java's own mechanism for 'inspecting' objects. When you do something like myObject.getClass(), what you're returning is still not a "reference to a class prototype". It's an instance of type Class. I.e. even in java, you can't do myObject.getClass().aStaticProperty. But you can use the getFields method provided by the Class class to obtain Field objects, and inspect their value with respect to specific object instances; for static fields, this instance simply becomes the null object.

Inheritance in matlab

I am having some trouble with matlab. I am working with b-splines. Sometimes I want to work with the actual spline, while other times I only want to use the so-called basis functions. Without diving into the theory of b-splines, the practical difference is that the when I want to work with the b-spline, I need an extra method and property. I want this property to be initialized by passing it in the constructor.
What I have so far (with most irrelevant methods and properties removed) hopefully roughly demonstrates the behavior that I want:
bsplinespace.m:
classdef bsplinespace < handle
properties
p % polynomial degree
end
methods
function result = bsplinespace(p)
result.p = p;
end
end
end
bspline.m:
classdef bspline < bsplinespace
properties
controlpoints
end
methods
function result = bspline(p, controlpoints)
result.controlpoints = controlpoints;
end
function result = getp(this)
result = this.p;
end
end
end
However, in this scenario the bspline constructor calls the bsplinespace constructor without passing any arguments, causing it to crash:
Not enough input arguments.
Error in bsplinespace (line 8)
result.p = p;
Error in bspline (line 7)
function result = bspline(p, controlpoints)
To be more explicit, what I want is:
One class bsplinespace, which has a constructor which accepts one parameter p
A class bspline, which is the same, but has an extra property and method
Is there an elegant way to implement this?
In your constructor method for bspline, you need to explicitly call the superclass constructor with input argument p:
function result = bspline(p, controlpoints)
result#bsplinespace(p)
result.controlpoints = controlpoints;
end
Otherwise MATLAB will call the superclass constructor with zero input arguments, and you'll get the error you're seeing.
It's a perfectly sensible design, and allows you to control the details of how arguments to the subclass constructor are passed through to the superclass constructor (or not, if you'd like to provide default arguments instead).

MATLAB CLASSES getter and setters

I come from a Java background. I am having issues with classes in Matlab particularly getters and setters. getting a message saying conflict between handle and value class I'm a little lost with what to do so any help for lack of a better word will be helpful.
classdef Person
properties(Access = private)
name;
age;
end
methods
% class constructor
function obj = Person(age,name)
obj.age = age;
obj.name = name;
end
%getters
function name = get.name(obj)
end
function age = get.age(obj)
end
%setters
function value = set.name(obj,name)
end
function value = set.age(obj,age)
end
end
end
Implementation
Since your class is currently a subclass of the default Value class, your setters need to return the modified object:
function obj = set.name(obj,name)
end
function obj = set.age(obj,age)
end
From the documention: "If you pass [a value class] to a function, the function must return the modified object." And in particular: "In value classes, methods ... that modify the object must return a modified object to copy over the existing object variable".
Handle classes (classdef Person < handle) do not need to return the modified object (like returning void):
function [] = set.name(obj,name)
end
function [] = set.age(obj,age)
end
Value vs. Handle
Going a bit deeper, the difference between a Value class and a Handle class lies mostly in assignment:
Assigning a Value class instance to a variable creates a copy of that class.
Assigning a Handle class instance to a variable create a reference (alias) to that instance.
The Mathworks has a good rundown on this topic.
To paraphrase their illustration, the behavior of a Value class is
% p is an instance of Polynomial
p = Polynomial();
% p2 is also an instance of Polynomial with p's state at assignment
p2 = p;
and of a Handle class is
% db is an instance of Database
db = Database();
% db2 is a reference to the db instance
db2 = db;
Quick'n Dirty from the Java perspective:
- "handle" classes are what your mind is set to. proper object instances with pointers to them. use them.
- "value" classes are always returning a full clone of whatever object (which has been modified by what you just did, e.g. setting a name).
the reason they have both in Matlab is that in Matlab you would expect the "value" behaviour natively. Imagine you have a matrix A = [1 2; 3 4], then assign that via B = A. if you now set B(1) = -1 you'd hope that A(1) is still 1, right? this is because matlab keeps track of "copies" and truly creates them as you modify different variables initially set to the same matrix. in OOP you'd have A(1)=-1 now as everythings an object reference.
furthermore, "native" matlab routines dont have a "this/self/me" variable that contains the instance reference to access from within functions. instead, the convention is that the class instance will be prepended to the function's argument list.
so for a function call myclass.mymethod(arg1,arg1), the declaration must be
function mymethod(this, arg1, arg2)
% Note that the name you choose for "this" is arbitrary!
end
mind you, this is the java-perspective (and also my favourite one), the above function call is equivalent to mymethod(myclass,arg1,arg1). this is more native to matlab-style, but somehow makes it harder to see you're calling an objects method.
now, regarding setters/getters: for handle classes, everything feels java-ish now:
classdef MyClass < handle
properties
MyProp;
end
methods
function set.MyProp(this, value) %Note: setMyProp is also valid!
... % do checks etc, trigger calls,
this.MyProp = value;
end
function value = get.MyProp(this)
... % notify, update, triggers etc
value = this.MyProp;
end
end
Of course it goes without saying that you dont need to define a getter if you just want to return the value, i.e. myclassinstance.MyProp will work without any just as well.
Finally, getters/setters for value classes are something that [never encountered me/i never needed] in my 7 years of matlab oop, so my advise would be to go with handle classes and enjoy happy matlab coding :-)
otherwise, the above explanation & official matlab docs is doing the job for value class getter/setters.

Matlab - Combining enumeration classes with non-static methods

I am attempting to combine an enumeration class with non-static methods in Matlab. I wish to create a 'LogEvent' class, which has the function 'log' which takes as an input argument an enumeration member (such as LogEvent.INFO, LogEvent.ERROR, or LogEvent.WARNING) and a string, for the purpose of appending this message in a file. I wish to use this LogEvent class repeatedly, for different programs, and as such the class has the property 'fileName' which is specified during construction and refers to the output file. Below is the code forming my classdef file:
classdef LogEvent
%Class definition for logging events.
properties
fileName;
end
methods
function obj = LogEvent(outFile)
obj.fileName = outFile;
end
function log(obj,type,logStr)
switch (type)
case LogEvent.INFO
typeStr = 'INFO';
case LogEvent.WARNING
typeStr = 'WARNING';
case LogEvent.ERROR
typeStr = 'ERROR';
end
FID = fopen(obj.fileName,'a');
Str = sprintf('%s - %s: %s\n',datestr(now),typeStr,logStr);
fprintf(FID,Str);
fclose(FID);
end
end
enumeration
INFO,
WARNING,
ERROR
end
end
Now admittedly I don't have a lot of experience programming so I may be approaching this the completely wrong way, though I have tried googling this problem but with little result - I may not know some particular keywords which would 'hit the nail on the head'. It is my belief though because multiple instances of this class need to be created (to refer to different files), the 'log' function needs to be non-static. I get this error message attempting to create an instance of this class though:
Error using LogEvent
While creating an instance of class 'LogEvent':
No value has been provided for the enumeration member named 'INFO'. For an
enumeration derived from a built-in class, a value must be provided for each
enumeration member.
Error in ZOHB (line 10)
obj.Log = LogEvent('ZOHB.log');
Inside the 'ZOHB' class, I attempt to create an instance of the LogEvent class, and assign it as a property of the ZOHB class.
In Matlab's enumeration scheme, the enumerated values must be instances of the class containing the enum. So e.g. WARNING would have to a certain LogEventinstance.
E.g. like in this example from the docs:
classdef Bearing < uint32
enumeration
North (0)
East (90)
South (180)
West (270)
end
end
Which means in your case, you'd have to specify arguments which would fit your LogEvent-constructor - this is what the error message says, basically.
Which is of course totally nonsense in your use-case.
In your special case, you'd better make ERROR, WARNING and INFO constant properties:
properties (Constant)
INFO = 1;
WARNING = 2;
ERROR = 3;
end
You can access constants in a static manner, so your remaining code should pretty much work with this version.

Is it possible to add methods on the fly to MATLAB classes?

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?
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
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.
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.