Can I use @subClass folder inside @superClass folders to create a class hierarchy?
31 views (last 30 days)
Show older comments
I am working on creating a large set of classes in matlab, and the super-class/sub-class setup looks like it will be best. I also have been extensively using the @class folder setup in order to help keep the code set organized. I have several questions which I will ask in another post, but my main question here is whether I can put the @subClass folder inside of the @superClass folder. I really want to create a folder hierarchy of classes and their sub-classes and sub-sub-classes. I have tried this, and both folders look like they are in my matlab path (solid color in the directory panel).
However, I have not been able to call the sub-class constructor, nor its methods. Either
(a) the sub-class is not actually in the matlab path and I really do have to have all of the sub-classes and sub-sub-classes in their own @class directory in the direct matlab path (so, no hierarchy is possible and I should just forget this idea) or
(b) I need some additional way of calling the sub-class constructor and its associated methods. Would I need to add an associated method line to the superClass classdef? I have tried playing a few games with this, and reading the documentation, but I haven't gotten anything working.
Thanks, -Dan
0 Comments
Accepted Answer
Matt J
on 14 Apr 2017
Edited: Matt J
on 14 Apr 2017
No, you cannot nest @-folders this way. As described in the documentation on class folders an @-folder must not be placed in the MATLAB path while its parent folder must be placed in the path. The arrangement you describe would violate these rules.
0 Comments
More Answers (4)
Daniele Busi
on 1 Feb 2020
Edited: Daniele Busi
on 1 Feb 2020
The following workaround works for me in MATLAB R2019b.
In the same folder, define:
- A class, in the form of a single file or @ folder;
- A package with the same name of the class.
Now, the package can contain classes and functions, which can be accessed through the dotted notation you would use for a nested class.
Example:
myroot\parentclass.m %which contains a classdef
myroot\+parentclass %package folder
myroot\+parentclass\nestedclass.m %which contains a classdef
or
myroot\@parentclass %parent class folder
myroot\@parentclass\parentclass.m %parent classdef
myroot\@parentclass\parentmethod.m %parent class method
myroot\+parentclass %package folder
myroot\+parentclass\@nestedclass %nested class folder
myroot\+parentclass\@nestedclass\nestedclass.m %nested class classdef
myroot\+parentclass\@nestedclass\nestedmethod.m %nested class method
Now, if myroot is in the MATLAB path (it could also be a parent package), calling
x = parentclass();
x.parentmethod();
will go through the class definition, while
y = parentclass.nestedclass();
will construct an instance of the nested class.
In this way, the nested class is hidden from the MATLAB path, but is accessible through dotted notation.
Caveat #1: the package folder has precedence over the class definition. Hence, if you define a function called parentmethod.m inside +parentclass, then it will be called instead of @parentclass\parentmethod.m.
Caveat #2: if in parentclass.m you define a property
classdef parentclass
properties
ni = parentclass.nestedclass()
end
end
then you can access a nestedclass instance from any parentclass instance:
x = parentclass();
x.ni.nestedmethod();
0 Comments
Steven Lord
on 14 Apr 2017
Note that with the classdef-based class system, you don't need to define classes in directories whose names start with the at symbol @ if you define all the methods inside the classdef file. So you could have a directory structure with classdef files inside, and as long as the directories containing those files are on the path the classes will be accessible.
For instance, here I have a directory structure for organizing a library by genre. I have Abstract classes books, nonfiction, and fiction and a concrete subclass scifi that isa books and isa fiction. The directory c:\temp\classhierarchy and all its subdirectories are on the path, so the class files in those subdirectories are visible to MATLAB. Isaac Asimov's novel Foundation is science fiction, fiction, and a book but it is not (yet?) non-fiction.
>> which books, which nonfiction, which fiction, which scifi
c:\temp\classhierarchy\books.m % books constructor
c:\temp\classhierarchy\nonfiction\nonfiction.m % nonfiction constructor
c:\temp\classhierarchy\fiction\fiction.m % fiction constructor
c:\temp\classhierarchy\fiction\scifi\scifi.m % scifi constructor
>> B = scifi('Foundation')
B =
scifi with properties:
genre: 'science fiction'
title: 'Foundation'
>> isa(B, 'scifi')
ans =
logical
1
>> isa(B, 'fiction')
ans =
logical
1
>> isa(B, 'nonfiction')
ans =
logical
0
>> isa(B, 'books')
ans =
logical
1
Now I didn't necessarily need to make all those subdirectories: I could have put books.m and two subdirectories, fiction and nonfiction, in the main directory and had the subclasses of fiction and nonfiction in those subdirectories. This was a quick example I generated for illustration purposes.
3 Comments
Matt J
on 14 Apr 2017
Edited: Matt J
on 14 Apr 2017
All of the above are possible with classdef files just as easily as with @class folders
(1) Write a publish() method in the nonfiction.m classdef file and a different one in nonfiction.m
(2) All class methods in classdef files are still distinguishable from default MATLAB functions with the same name. All functions that are not classdef methods can be put in private/ folders or in packages, as Philip suggested.
(3) Still possible, but instead create a fantasy/ folder (without "@") containing the fantasy.m classdef file. The fantasy/ folder could also contain a private/ folder (see (2)) of other non-class functions that you want only the fantasy class to have access to.
Steven Lord
on 14 Apr 2017
Daniel:
0: Yes, classdef files can become long. There are techniques you can use to help organize the methods in a classdef file, like having dedicated methods blocks for different families of methods ( classdef files can contain multiple methods blocks, multiple properties blocks, etc.) that you can fold when you're not modifying them.
1: As Matt said, each of the subclasses can define their own implementation or can use their superclass's implementation (or can use their superclass's implementation in their own implementation, see the "Invoking Superclass Methods in Subclass Methods" section of that page.)
One case where the subclass MUST define its own implementation is when you have multiple inheritance and two or more of the superclasses define the same method -- if the subclass didn't define its own version of that same method, it would be ambiguous which would be called.
2: Yes, this assumes that all of your subclasses have their own subfolders. But if I were designing that class hierarchy for real, not just for an example, I might just have subfolders fiction and nonfiction (as the two main subdivisions of types of books) and put scifi.m, romance.m, dictionary.m, encyclopedia.m, atlas.m, cookbook.m, etc. in the appropriate subdivision.
Or I might make fiction and nonfiction properties of books, since there are books that might fall in both categories: the official Game of Thrones cookbook (a real cookbook offering recipes for making dishes described in a work of fiction) is one example. [Yes, there is such a book: A Feast of Ice and Fire: The Official Game of Thrones Companion Cookbook.]
Matt J:
3: If only the fantasy class needs these private non-class functions, you could even define them as class-related functions at the end of the classdef file, after the end that ends the classdef block.
Philip Borghesani
on 14 Apr 2017
As pointed out by others nested classes won't work. I would use a package:
myroot/@baseclass % or just myroot/baseclass.m
myroot/+baseSubclass/@subclass1
myroot/+baseSubclass/@subclass2
to construct just call cl=baseSubClass.subclass2(args)
0 Comments
Michael Kane
on 7 Jul 2018
There is a way to have a class folder within a class folder!
The key is to have an intermediate folder that is neither a class nor a package. Take the following directory structure for example.
myroot/@baseclass/
myroot/@baseclass/baseclass.m
myroot/@baseclass/baseclass_sub.m
myroot/@baseclass/lib/
myroot/@baseclass/lib/lib_func.m
myroot/@baseclass/lib/@lib_class/
myroot/@baseclass/lib/@lib_class/lib_class.m
myroot/@baseclass/lib/@lib_class/lib_class_sub.m
myroot/@baseclass/lib/+lib_pkg1/
myroot/@baseclass/lib/+lib_pkg1/pkg1_fun.m
myroot/@baseclass/lib/+lib_pkg2/
myroot/@baseclass/lib/+lib_pkg2/pkg2_fun.m
The key is to add the lib directory to the path when baseclass is constructed. For example
baseclass.m
classdef baseclass
methods
function baseclass
% Add the path of the lib directory within the
% directory of the class baseclass
addpath([fileparts(which(mfilename)) '\lib']);
% Adds to the path
% - lib_class
% - lib_func
% Add the packages that are within the lib directory
import lib_pkg1.pkg1_fun
import lib_pkg2.pkg2_fun
end % baseclass
end % methods
end % classdef
This will make lib_class, lib_func, pkg1_fun, and pkg2_fun available to the methods within baseclass. However, it will also make the classes and functions available to all other functions and methods in the workspace. So, this is really just good for directory organization, not making private subclasses.
This still abides by the rule Steven mentioned. Since that rule does not mandate that a directory with a class not be on the path
1 Comment
See Also
Categories
Find more on Construct and Work with Object Arrays in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!