I have a project in matlab with the following directory structure:
+namespace\
#class1\
class1.m
#class2\
class2.m
mainfile.m
in class1.m I have something like the following
classdef class1
%readonly variables
properties(GetAccess = 'public',SetAccess = 'private')
forename;
lastname;
middlename;
end
properties(Constant = true)
%in centipascals
p1 = class2(param1,param2); %this is the part I need to work
end
methods(Access = public)
function this = class1(fname,lname,mname)
this.forename = fname;
this.lastname = lname;
this.middlename = mname;
end
end
end
I can't seem to get this class working. Class1 doesn't recognize the constructor of class2 (probably because something isn't being imported correctly). How do I import class2 or what do I need to do in order to have other class instances as member variables?
In Matlab, you need to fully qualify references to classes in a namespace, even from other classes within that same namespace. Like this.
classdef class1
properties (Constant = true)
%in centipascals
p1 = namespace.class2(param1,param2);
end
end
You can import other classes from the same namespace, but imports only work at a per-function level, and don't work in properties blocks at all AFAIK, so it won't work in this specific case, and may be more trouble than it's worth elsewhere.
Related
I have following class definition under +mypackage\MyClass.m
classdef MyClass
properties
num
end
methods (Static)
function obj = with_five()
obj = MyClass(5);
end
end
methods
function obj = MyClass(num)
obj.num = num;
end
end
end
I use with_five() as a static factory method.
Following script should create two objects.
import mypackage.MyClass
class_test1 = MyClass(5);
class_test2 = MyClass.with_five();
class_test1 has been created.
For class_test2 it says:
Error using MyClass.with_five
Method 'with_five' is not defined for class 'MyClass' or is removed from MATLAB's search path.
Error in Testpackage (line 4)
class_test2 = MyClass.with_five();
When I put MyClass.m outside of a package folder and remove the "import" statement, it works.
What am I doing wrong?
There are several wonky things in MATLAB with packages and with static methods.
First, functions within a package must use the package name to reference other functions or classes within the same package (see here). So the static method mypackage.MyClass.with_five() must be declared as follows:
methods (Static)
function obj = with_five()
obj = mypackage.MyClass(5);
end
end
Without this, I see:
>> mypackage.MyClass.with_five
Undefined function or variable 'MyClass'.
Error in mypackage.MyClass.with_five (line 8)
obj = MyClass(5);
Second, static class methods (at least the ones for classes inside packages) are not loaded until an object of the class is created. So we need to call the class constructor first:
>> clear classes
>> mypackage.MyClass.with_five
Undefined variable "mypackage" or class "mypackage.MyClass.with_five".
>> mypackage.MyClass(1);
>> mypackage.MyClass.with_five
ans =
MyClass with properties:
num: 5
The same is true if we import the class:
>> clear classes
>> import mypackage.MyClass
>> MyClass.with_five
Undefined variable "mypackage" or class "mypackage.MyClass.with_five".
>> MyClass(3);
>> MyClass.with_five
ans =
MyClass with properties:
num: 5
This second point was true in R2017a (where the outputs above were generated), but is no longer true in R2021a. I don't know in which release of MATLAB this was fixed, but in R2021a it is no longer necessary to create an object of a class to use its static method.
I think what you are missing is the fact that when you import a static method, you have to import the class name and the method name (https://au.mathworks.com/help/matlab/matlab_oop/importing-classes.html)
This works:
classdef MyClass
properties
num
end
methods (Static)
function obj = with_five()
obj = MyClass(5);
end
end
methods
function obj = MyClass(num)
obj.num = num;
end
end
end
Then do the following:
>> import MyClass.with_five
>> x = with_five
Output:
x =
MyClass with properties:
num: 5
That being said: don't create an object in a member function of its own class! As you suggest, a better choice is to move the factory to a different class. If you wanted to make a bunch of chainsaws, you would never go about trying to design a chainsaw that has a button on it that builds chainsaws. You would rather design a factory that can produce chainsaws that are designed to cut down trees.
A 'static factory' is not a bad thing. This is actually a pretty common pattern especially in C#. However, the factory is always its own class. Calling that method from another object that inherits from or extends that class (which I'm not sure you can even do in Matlab...) would most certainly be confusing if not deadly. I also can't think of any reason you would ever need to do this. In fact I don't understand why with_five() should be static at all
In Matlab I have the package "+mypackage". All the following definitions are under this folder/package.
MyClass.m
classdef MyClass
properties
prop1 MyProperty
end
methods (Static)
function obj = with_five()
obj = mypackage.MyClass(5);
end
end
methods
function obj = MyClass(num)
obj.prop1 = mypackage.MyProperty(num);
end
end
end
MyProperty.m
classdef MyProperty
properties
num double
end
methods
function obj = MyProperty(val)
obj.num = val;
end
end
end
So in MyClass.m I define the prop1 property to be an object of class MyProperty.
Now I would like to create objects with this script.
import mypackage.MyClass
class_test1 = MyClass(5);
class_test2 = MyClass.with_five();
When I run it I get following errors:
Error using Testpackage (line 3)
Error defining property 'prop1' of class 'mypackage.MyClass':
Class named 'MyProperty' is undefined or does not support property validation.
When I remove the property definition from MyClass.m it works.
Is there a way to define properties to be an object of an own class in Matlab?
Thank you Wolfie your Help!
I changed the definition for prop1 to mypackage.MyProperty.
My Class definition looks now like this:
classdef MyClass
properties
prop1 mypackage.MyProperty
end
methods (Static)
function obj = with_five()
obj = mypackage.MyClass(5);
end
end
methods
function obj = MyClass(num)
obj.prop1 = mypackage.MyProperty(num);
end
end
end
Its necessary to point to MyProperty inside my package mypackage.
Otherwise Matlab is not able to find it.
I found it in the Matlab help:
https://de.mathworks.com/help/matlab/matlab_oop/scoping-classes-with-packages.html?s_tid=srchtitle#brfynt_-3
I've made a mistake and recorded a bunch of important data using a class definition that I can't find anymore. The methods are not important, I just want the data; a struct conversion would be fine.
Is there any way I can recover this?
Googling it did not help.
The solution is to create a new class that overloads the loadobj method. See here for more information regarding the load process for classes.
I replicated your problem by creating a class:
classdef myclass
properties
Prop1
Prop2
Prop3
end
methods
function obj = myclass(a,b,c)
obj.Prop1 = a;
obj.Prop2 = b;
obj.Prop3 = c;
end
end
end
Then I created an object of this class and saving it to a file "x.mat":
x = myclass('a',56,[1,2,3]);
save x
Next, I deleted the myclass file and did clear classes. This put me in your situation.
I then created a new myclass class that overloads the loadobj method:
classdef myclass
properties
data
end
methods (Static)
function obj = loadobj(s)
obj = myclass;
obj.data = s;
end
end
end
Note how it doesn't know any of the original properties. This does not matter. If any of the original properties is missing when loading an object from a MAT-file, loadobj will be called with s being a struct containing all the properties of the original object.
With this new class definition, load x created an object x of class myclass, where x.data was a struct containing the properties of the object saved in "x.mat".
How can I avoid repeating a long tedious package name in matlab classes in the following cases:
When specifying the Superclass, e.g. classdef Class < tediouspkgname.Superclass
When calling the superclass constructor, e.g. obj = obj#tediouspkgname.Superclass(...).
When calling superclass methods, e.g. val = somefunc#tediouspkgname.Superclas(...).
I'm looking for an equivalent of matlabs import statement, which is not usable in these cases unfortunately.
MWE:
Lets have a folder called +tediouspkgname/ in our Matlab path. So Matlab recognizes there's a package called tediouspkgname.
Lets have a Class ExampleClass which is saved in the file +tediouspkgname/ExampleClass.m:
classdef ExampleClass
properties
p
end
methods
function obj = ExampleClass(p)
obj.p = p;
end
function print(obj)
fprintf('p=%s\n',obj.p);
end
end
end
Let there be another Class, derived from ExampleClass, living in the file
+tediouspkgname/DerivedClass.m:
classdef DerivedClass < tediouspkgname.ExampleClass
methods
function obj = DerivedClass(p)
obj = obj#tediouspkgname.ExampleClass(p);
end
function print(obj)
print#tediouspkgname.ExampleClass(obj);
fprintf('--Derived.\n');
end
end
end
I want the following commands to work without errors while mentioning tediouspkgname. as little as possible:
e = tediouspkgname.ExampleClass('Hello');
e.print();
o = tediouspkgname.DerivedClass('World');
o.print();
In particular, this definition of DerivedClass gives me the error ExampleClass is not a valid base class:
classdef DerivedClass < tediouspkgname.ExampleClass
methods
function obj = DerivedClass(p)
obj = obj#tediouspkgname.ExampleClass(p);
end
function print(obj)
import tediouspkgname.ExampleClass
print#ExampleClass(obj);
fprintf('--Derived.\n');
end
end
end
You have two examples at the command line:
e = tediouspkgname.ExampleClass('Hello');
e.print();
o = tediouspkgname.DerivedClass('World');
o.print();
For these cases, you can use import at the command line:
import tediouspkgname.*
e = ExampleClass('Hello');
e.print();
o = DerivedClass('World');
o.print();
and it should work fine.
For the other cases you have (in the class definition line, and when calling a superclass method), you need to use the fully qualified name including the package.
I dislike this aspect of the MATLAB OO system. It's not just that it's tedious to write out the fully qualified name; it means that if you change the name of your package, or move a class from one package to another, you have to manually go through your whole codebase in order to find-and-replace one package name for another.
As you know we can define class definition and method definition in separate files in #folder. How we can do that if we have attributes for method? I read in MATLAB OOP documentation that we should use this structure in method file:
classdef myClass
method (att = value,...)
tdata = testdata(obj,arg1,arg2)
end
end
But we have another file (myClass) in this folder for class definition so if we have this structure we have two class definition files. one of them has properties definition and another has methods properties (two files with same name!). If we change above classdef name(myClass) to function name(testdata), we have a error in MATLAB. What should I do?
If you're defining your class using an #-folder and separate files, you don't need two class definition files. You need a single class definition file (which is basically as you've defined in your question) and a separate file that contains just your method, implemented as a function.
For example:
#MyClass\MyClass.m
classdef MyClass
properties (GetAccess = public, SetAccess = private)
myGreeting
end
methods (Access = public)
function obj = MyClass
obj.myGreeting= 'hello'
end
function sayhello(obj, name)
txt = obj.getText(name);
disp(txt)
end
end
methods (Access = private)
txt = getText(obj, name)
end
end
#MyClass\getText.m
function txt = getText(obj, name)
txt = [obj.myGreeting, ' ', name];
end
Note that you only need to include the stub definition of the method within the class definition file if you need to modify the method attributes from default. If it's a public method (and non-Static, non-Hidden, non-Sealed, non-Abstract etc), you don't need to include it at all, you just need to include the file in the #-folder.