MATLAB Answers

0

Can I use @subClass folder inside @superClass folders to create a class hierarchy?

Asked by D. Plotnick on 13 Apr 2017
Latest activity Commented on by Michael Kane on 8 Jul 2018
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

Sign in to comment.

4 Answers

Answer by Matt J
on 14 Apr 2017
Edited by Matt J
on 14 Apr 2017
 Accepted Answer

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

Sign in to comment.


Answer by 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

Wow, I was unaware of the ability to use abstract classes. That is much closer to what I need. Thanks!
With regards to the file structure, I thought that there were three main reasons for wanting to use the @class folder technique.
(0) added this one - it avoids putting all of my class methods functions in a single very long *.m file, which will get unwieldy fast.
(1) You can have multiple functions of the same name, but different functionality. Continuing your example, maybe I want two different functions both called publish but that will behave differently for 'fiction' and 'non-fiction'. I could conceivably just have the same function be a method for both classes, and include a switch-case section in the function, but this will get unwieldy for larger code sets.
(2) It prevents you from having to add all of the sub-folders to your matlab path. That way I can have methods with the same name as default matlab functions and not have ambiguity. This is also a concern when I give code to other people who like to keep their matlab path clear except when running the code itself. Typically I will use addPath and then rmPath at the top and bottom of the mainfile, and with the @class structure I only need add the top package folder.
(3) It allows for easy organization. If I then write a 'fantasy' genre class which is also isa('books') and isa('fiction'), I can drop the @fantasy folder into my class-heirarchy package.
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.
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.

Sign in to comment.


Answer by 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

Sign in to comment.


Answer by 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

NOTE: The trick above works in Matlab2018a, but not in 2016b.

Sign in to comment.