MatLab OOP Setting a Property via a Utility Method - matlab

I'm trying to change a property in a class called houses via a utility method which is Static. I'm getting terribly confused with the reference obj as I don't know when and where it should be used. I am trying to bypass the constructor method so I can access the setProperty method, but I am getting errors such as too many output arguments. I've tried passing in obj as well as x, but I get similar errors. However, I can change the property a if I pass in a value to the constructor method.
classdef houses
properties
a;
end
methods
% constructor method
function obj = houses()
end
end
methods (Static)
function setProperty(x)
obj.a = x;
end
end
end

In general, you should not use static methods to set properties of a class. If your property is public, then you can use a static method but it is highly recommended that you do not. If your property is private/protected, then you definitely cannot use a static method to modify it.
Your class should look like this then (I took the liberty of stating explicitly the access properties of each block):
classdef houses
properties (Access = private)
a;
end
methods (Access = public)
% constructor method
function obj = houses()
end
function SetA(obj, a)
obj.a = a;
end
function DoSomething(obj, more_parameters)
% Lengthy stuff here
end
end
end
Now, regarding your question about obj: the answer is you must pass obj as the first argument of every instance method. The variable obj refers to the current instance of the class in a generic way. See for example the method DoSomething.
Static methods do not have access to any of the properties of the class, unless public. As such, when declaring a static method, you should not pass the obj variable.
Last thing: always use explicit access modifiers for your properties and methods. It will save you some headaches.

A static method is not typically supposed to access an object (hence it does not have access to obj).
If you want to modify a static propperty (shared by all objects, and the class itself), you can use something like:
classdef houses
properties (Static)
a;
end
methods
% constructor method
function obj = houses()
end
end
methods (Static)
function setProperty(x)
houses.a = x;
end
end
end
Regarding obj, it is the 1st argument of every methods (non static). So when you do:
o = myClass();
o.myMethod(args);
Matlab will see this as:
myMethod(o, args);
So when you define the method, you have to put obj as the 1st argument (in fact you can choose any name, it does not have to be obj).

Related

Matlab: How to restict access to sub-class of abstract class method

Lets have a following three classes:
% Main class
classdef MjrClass < handle
properties (SetAccess = immutable, GetAccess = public)
cls;
end
methods (Access = public)
function self = MjrClass()
self.cls = SubClass(2);
end
end
end
% Abstract class
classdef (Abstract) AbsClass < handle
properties (SetAccess = immutable, GetAccess = protected)
p;
end
methods (Access = {?MjrClass})
function self = AbsClass(parent)
self.p = parent;
self.do();
end
end
methods (Access = public)
function show(self)
fprintf('self.p: %d\nself.c: %d\n', self.p, self.c)
end
end
end
% Sub-Class
classdef SubClass < AbsClass
properties (SetAccess = private, GetAccess = public)
c;
end
methods (Access = private)
function do(self)
self.c = self.p*2;
end
end
end
The logic is following. Main class MjrClass defines interface for end user. Inside, it creates (in general) several instances of SubClass class. Since those share some properties and methods they all inherit from AbsClass class. And because the AbsClass class alone has no purpose, it is defined as abstract class.
However as it is, Matlab complains it "Cannot access method 'AbsClass' in class 'AbsClass'". The problem is obviously the Access property of constructor method. But if I leave it public it does not reflect the fact that it shoould be instantiated only within MjrClass class.
The same problem applies to do() method of SubClass class, where Access = private should restrict the method to be called only once within the AbsClass constructor, not allowing user to call it.
The access specifier for the AbsClass constructor doesn't actually allow AbsClass to call that method. So, the fix is simple, allow AbsClass (and its subclasses) to call its own constructor, like this:
methods (Access = {?MjrClass, ?AbsClass})
function obj = AbsClass(...)
....

Force conversion of struct to object in MATLAB loadobj function

I am working with a custom defined class I called "PathObj_Standard". I want to make sure that when I load this class, if the property CalcDate was saved as a cell array it is converted to a standard array. However, I changed the class definition some time ago, so when I use the loadobj function, I am getting a struct instead of an object. The original code I'm using has a lot more properties, so I'd rather not create a new object by assigning property by property from the struct to a new object. Furthermore, I'm also hesitant to change the constructor to accept a struct as an argument.
I tried using the class function inside loadobj, but I am getting a Cannot redefine class 'PathObj_Standard' without a call to 'clear classes' error. Isn't this function supposed to force conversion of a struct to an object? Why doesn't it work within the loadobj function?
classdef PathObj_Standard < handle
properties (SetAccess = protected)
CalcDate;
Name;
end
methods(Static)
function obj=loadobj(s)
if isstruct(s)
obj=class(s,'PathObj_Standard');
else
obj=s;
end
if not(isempty(obj.CalcDate)) && iscell(obj.CalcDate)
obj.CalcDate=cell2mat(obj.CalcDate);
end
end
end
methods
function obj=PathObj_Standard(Name,CalcDate)
obj.Name=Name;
obj.CalcDate=CalcDate;
end
end
The issue is that calling class attempts to create a class which you can't do from within your loadobj. You'll want to call the actual constructor
Also in my experience, the easiest way to construct a class from a struct is to inherit from hgsetget rather than handle as that automatically has the set and get methods of MATLAB's graphics objects and these methods can accept property/values in the form of a struct. In newer versions of MATLAB, you can also use the SetGet mixin
classdef PathObj_Standard < hgsetget
If you do this, you could change your loadobj method to be something like
function obj = loadobj(s)
% Update the input struct as needed
if isfield(s, 'CalcDate') && ~isempty(s.CalcDate) && iscell(s.CalcDate)
s.CalcDate = cell2mat(s.CalcDate);
end
% Call the default constructor
obj = PathObj_Standard();
% Update all properties that were supplied to loadobj
set(obj, s)
end

Classname in static methods of abstract classes

I would like to access the class name of the concrete class that's invoking a static method implemented in an abstract superclass.
This is the code (part of) of the abstract superclasss:
classdef (Abstract) AbstractJobProcessor < handle
properties (Abstract, Constant)
VERSION_MAJOR;
VERSION_MINOR;
LAST_MODIFIED;
end
...
methods (Static)
function res = getVersionMajor;
res = AbstractJobProcessor.VERSION_MAJOR;
end
function res = getVersionMinor
res = AbstractJobProcessor.VERSION_MINOR;
end
function res = getVersionInfo
res = sprintf('**CLASSNAME**: v%d.%02d (last modified: %s)',...
AbstractJobProcessor.VERSION_MAJOR,...
AbstractJobProcessor.VERSION_MINOR,...
AbstractJobProcessor.LAST_MODIFIED);
end
end
...
Basically, I would like to access the classname of the concrete subclass and use it in the method getVersionInfo in place of the string **CLASSNAME**.
All the methods returning meta information about a class (that I have found in the documentation) require a reference to an instance of the class (like, for example, mc = metaclass(object)).
The below function will give you what you want - subclass name, that was used when invoking an (inherited) static superclass method. Just call it inside your superclass method like you would any normal function:
className = getStaticCallingClassName();
What it does handle:
Both the case when method was invoked programmatically (i.e. by a running script / function), as well as when it was invoked from the command window.
Arbitrarily nested package names (i.e. classes located inside directories prefixed with +).
What it does not handle:
Does not work if the static method is called in a non-static context, i.e. on an object instance. But you should not be using such syntax anyway. This would've been possible if we were able to use evalin with 'caller' workspace recursively, but it does not work this way.
A brief explanation behind the idea: second entry in the stack trace, produced by dbstack, would correspond to the superclass, which we can use to extract the static method name. The next steps depend on:
If the method is invoked programmatically, third stack entry would point us to a line in the the parent script/function which we need to read, e.g. using dbtype. All that's left to do is extract the subclass name using regexp based on the method name.
If the method is invoked from command window, we query the last command and use that as the input for our regular expression.
Note that even if stack has 3 entries or more, it doesn't mean that the method was invoked programmatically. For example, if we've stopped on a breakpoint somewhere and invoke the method from command window, stack trace would be long, but regexp based on the line from the third stack trace entry will not give us the answer. In this case we fall back to the command window approach.
Warning: it heavily relies on undocumented features and may break in any feature release. Tested on Matlab 2015b, but should work on most previous releases as well. Some may say it is quite dirty, but it works very well, and it's the only method that I'm aware of to achieve such a behavior.
function [className, fullPath] = getStaticCallingClassName()
ST = dbstack('-completenames');
% First one is getStaticCallingClassName, second one is the superclass
methodName = char(regexp(ST(2).name, '[^\.]([^.]*)$', 'match'));
% matches string (combination of alphanumeric/underscore/dot characters) preceeding the given method call.
pattern = sprintf('[\\w.-]*(?=.%s)', methodName);
% If the parent called static method programmatically, we should be able to find it via the next (third) stack trace
if length(ST) > 2
command = evalc('dbtype(ST(3).file, num2str(ST(3).line))');
className = char(regexp(command, pattern, 'match'));
else % was likely called from command window. Long stack trace means that we're simply waiting in a breakpoint somewhere
className = []; % go straight to command window approach
end
if isempty(className) % means that static method was called directly from command window
javaHistory = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory();
command = char(javaHistory(end));
className = char(regexp(command, pattern, 'match'));
end
fullPath = which(className);
end
Here's a workaround. According to the MATLAB documentation:
'Ordinary methods define functions that operate on objects of the class',
'Static methods are (1) associated with a class, but (2) not with specific instances of that class'.
You can have both aspects of static methods if you call an ordinary method with an empty object array.
For example, suppose we have a base class:
classdef base
methods
function obj = base()
disp('constructor called')
end
function dispClassName(obj)
disp(['class name = ', class(obj)]);
end
end
end
and a subclass
classdef sub < base
end
Now call the methods as follows (this will not invoke any constructor):
>> base.empty.dispClassName
class name = base
>> sub.empty.dispClassName
class name = sub
A real solution (for which I did an enhancement request 03315500 to MathWorks) would be to extend the MATLAB language with a method attribute 'Class' to define methods that are associated with the invoking class (similar to the Python #classmethod decorator). Methods of this class would automatically receive the metaclass of the invoking function as a first argument. With such an extension we could define a base class:
% Future MATLAB syntax extension
classdef base
methods(Class) % New method attribute ‘Class’
function dispClassName(cls) % implicit argument (meta.class)
disp(['class name = ' cls.Name ]);
end
end
end
and a subclass
classdef sub < base
end
and call
>> base.dispClassName
class name = base
>> sub.dispClassName
class name = sub

How to call function in classdef matlab

I have a class and a function, I want to put function in class a just wanted to call the whole in another class, but it gives the certain error while calling, Is it a possibility to call function without calling it in Class constructor? I'm currently calling in class constructor but other possible way is more likely. Five arguments are required in func, how can I make that function a class?
I have tried also in constructor while input argument is giving obj.arg1=arg1;
My Code:
classdef myClass
properties
node;
end
properties (Access=private)
end
methods
function obj = myClass()
func(obj,obj,obj,obj,obj);
end
function node = func(arg1,arg2,arg3,arg4,arg5)
%some operation
end
end
You want to have a separate methods(Static) section for those functions you want to call without instantiating an instance of your class. For any methods in the static section, you can do from another file:
<some code here>
answer = myClass.myStaticMethod(args);
<rest of code here>
Whereas for anything in the generic methods block without (Static) you would have to instantiate the class and then call methods against the instance, i.e.:
<some code here>
classInstance = myClass(constructor args)
answer = classInstance.myNonStaticMethod(args);
<rest of code here>

Protected property is not accessible if defined as abstract

Using Matlab R2012a, I have the following class hierarchy:
classdef Parent < handle
properties (Abstract, SetAccess = protected)
Limit
end
end
classdef SimpleChild < Parent
properties (SetAccess = protected)
Limit = 1.0
end
end
classdef ExtendedChild < Parent
properties (Access = private)
Child = SimpleChild
end
properties (Dependent, SetAccess = protected)
Limit
end
methods
function this = ExtendedChild
this.Limit = 2;
end
function output = get.Limit(this)
output = this.Child.Limit;
end
function set.Limit(this,input)
this.Child.Limit = input;
end
end
end
This a simple example where the "Parent" class defines an abstract "Limit" property, which is implemented in both the "SimpleChild" and the "ExtendedChild" class. The "ExtendedChild" class encapsulates a private instance on the "SimpleChild" class and forward the access methods (get/set) to the private instance. Constructing an "ExtendedChild" instance fails with the following message:
>> obj = ExtendedChild
Setting the 'Limit' property of the 'SimpleChild' class is not allowed.
Error in ExtendedChild/set.Limit (line 16)
this.Child.Limit = input;
Error in ExtendedChild (line 10)
this.Limit = 2;
I would have expected the "Limit" property to be settable since it is defined in the "Parent" class with a protected SetAccess. I can make the problem disappear if the property is implemented directly in the "Parent" class, but then I cannot redefine it as dependent in the "ExtendedChild" class, which is the point of the construction (separation of interface and implementation).
Can someone tell me if I'm doing something wrong?
Since the Limit property of SimpleChild is protected, you can only set its value from SimpleChild or a subclass of SimpleChild, which is not the case for ExtendedChild.
I'm not entirely sure what you're trying to achieve, so can't really advise on what the "best" way to do it might be. But I would guess that whatever you want, it's unlikely that having a set method for a Dependent property is the right way to achieve it - there are only very rare reasons why you might want to do that.