Time is no object
I’ve been wishing to dabble in Object Oriented Programming (OOP) for a while. Despite understanding the core concepts, however, the jargon and my limited knowledge of OOP-centered languages has kept me at bay. Only 2 problems really that can be solved thus:
- Jargon
- If you can’t beat them,
joinsimplify them. If I can explain the jargon to someone else (you), it will stop being an issue
- If you can’t beat them,
- Knowledge
- While my knowledge of languages like Python, Ruby and Objective-C is at its infancy, I’m rather familiar with Matlab. And Matlab has (mostly-ignored) Object Oriented capabilities
To learn something well, teach build it
To learn OOP in Matlab, I decided to build a scientific toolbox for analysing multimedia data, since some of my current projects require this.
…well, re-build. The toolbox existed before but used a rather messy set of procedural scripts and functions. If only I could steal acquire the knowledge… Thankfully, there is one or two excellent reference guides that are generally clearer than Matlab’s own documentation.
I made a neat little Visual Analysis toolbox (which remains work in progress) and learned a lot about:
- Packages
- Classes
- Properties
- Methods
- Objects
- Inheritance
- Dynamic Dispatch
I’ve got a package for you!
An optional thing to do when delving into OOP Matlab is to make a package. A package consists of a folder where all your classes will be stored. Let’s try making one in Matlab.
>> mkdir +package
>> cd +package
Doing it with class
Inside the package, we can start creating class files. Because our new class is excellent, let’s call it superclass…
>> edit superclass.m
Inside, we will need to define it, so it will look something like
classdef superclass
% SUPERCLASS is an excellent class
properties
end
methods
end
end
Right now our class is rather empty, let’s fill ‘er up.
Properties, the proper way
We can add some properties to our class. What’s nice is that we can hide them from prying eyes and keyboards if needed. We will have a few different ones:
- Public:
- Available to everyone to change inside and outside the class
- Protected:
- Available to this class and any of its subclasses
- Private:
- Available only to this class
Let’s go back to our class and make some properties, we can have a couple of property blocks:
[...]
properties
clothes
end
properties (SetAccess = 'protected')
face
end
properties (SetAccess = 'private', GetAccess = 'private')
heart
end
properties (Constant = true)
MORTAL = true;
end
[...]
We are letting anyone look at and touch our clothes, they are public because they are not very important.
Our face is a bit more protected, so only our children (i.e. subclasses) can touch it, though in this case everyone can see it (GetAccess remains public).
Our heart has been broken so many times that we keep it private, never letting anyone see or touch it anymore (sniff…!).
Some other things about us are constant and can’t be changed, like the fact that we are MORTAL.
Crystal clear methods
We will need a couple of methods in our class. One of these has to be a constructor. Again, we can make several method blocks.
[...]
methods
% This is the constructor
function obj = superclass(clothes, face, heart)
if(nargin == 3)
obj.clothes = clothes;
obj.face = face;
obj.heart = heart;
else
warning('A superclass needs clothes, a face and a heart')
end
end
function obj = program(obj)
fprintf('Clack, clack, clack\n')
end
end
methods (Access = 'private')
function obj = sleep(obj)
fprintf('ZzzzZ\n')
end
end
methods (Static = true)
function soul()
fprintf('Some immortal soul will be reincarnated into the next instance\n')
end
end
[...]
The constructor method makes an instance of our superclass class. It is a public method, since otherwise you’d not be able to make an instance.
The instance method program is also public, as it’s something that can be accessed (i.e. called) and requested by anyone (i.e. you can, in theory, ask me to program something).
The instance method sleep is private though, as it’s something that can only be accessed within the class (i.e. I’ll decide when to sleep myself!).
The class method soul is static, as it can be accessed without making an object instance (i.e. this example works with the assumption that an immortal soul exists).
I object
There’s little point to make a class unless you want to make objects. Still, let’s try the static method:
>> cd .. % We need to be outside the package folder to call it
>> package.superclass.soul() % 'package.' is only needed if the class is inside a package
Without much ado, let’s also make an instance of it:
>> Vader = package.superclass('robe', 1, false);
We have created a superclass object called Vader wearing a robe, having 1 face and no heart. Let’s see if he knows programming…
>> Vader.program();
He does! Let’s make him sleep…
>> Vader.sleep();
Seems like we can’t make him sleep. For our insolence he’s likely to do a Jedi choke. Maybe if he has some heart he won’t do it though…
>> Vader.heart
…we will never know!
The meek subclass shall inherit the earth superclass
Now that we have an excellent superclass, we can make a subclass that will inherit properties and methods from it.
>> cd +package
>> edit subclass.m
Since we want to just see what we’ve inherited, let’s make it simple but add a simple constructor:
classdef subclass < superclass
% SUBCLASS is a subpar class
properties
end
methods
function obj = superclass(clothes, face, heart)
if(nargin == 3)
obj.clothes = clothes;
obj.face = face;
obj.heart = heart;
else
warning('A subclass needs clothes, a face and a heart')
end
end
end
end
Let’s see if we can make an instance of it:
>> cd ..
>> Luke = package.subclass('robe', 1, true)
Seems like we can’t. The heart property we’d have wished to inherit from superclass is private to the superclass. But we can adjust our constructor:
[...]
function obj = superclass(clothes, face, heart)
if(nargin == 2)
obj.clothes = clothes;
obj.face = face;
else
warning('A subclass needs clothes and a face')
end
end
[...]
Heartless, I know, but we have little choice. Still, Luke is still able to do some of the things his father parent class can do:
>> Luke = package.subclass('robe', 1)
>> Luke.program();
>> Luke.sleep();
So, he’s still has some programming talent but has some sleepless nights in store, since the sleep method from superclass is private. Also, notice that the superclass constructor is called with 0 arguments, in case it needs to do something important. In this case, it just reminds us that Luke is a subclass, since he is heartless.
Dynamic duo dispatch
Let’s power up Luke’s programming to make up for his faults. We can add our own program method that will override the superclass method.
[...]
function obj = program(obj)
fprintf('Click, click, click, click\n')
end
[...]
This should work…
>> Luke = package.subclass('robe', 1)
>> Luke.program();
We can call this differently too:
>> program(Luke);
This is the start of method overloading, which means that we can make the same method call do different things depending on the object that calls it. We can do the same with matlab functions like sum() and plot().
Let’s overload the plot method in our superclass, by adding a new method:
[...]
function obj = plot(obj)
image('Vader.png');
end
[...]
So when we call the plot method on our superclass, it will try to display the ‘Vader.png’ image (I hope you have a good one!), instead of using the matlab plot() function. So after recreating our Vader object anew from our updated superclass, let’s try this method:
>> plot(Vader)
Again, thanks to dynamic dispatch we can have a different plot method in our subclass to instead display the entire Star Wars Episode IV movie in ASCii:
[...]
function obj = plot(obj)
unix('telnet towel.blinkenlights.nl');
end
[...]
If you call this one, get your geeky hat on and some popcorn };–)