Objects in OpenMatrix Language

Objects in OML are defined using the classdef keyword. This creates a blueprint for an object but does not actually create (instantiate) anything.

There are three parts to defining an object:
  • The declaration including the name and parent class.
  • The properties section.
  • The methods section.
A class defined by the classdef keyword has a name, which must be a valid OML function name.
classdef MyClass
end
Properties of an object act in a similar manner to structs.
classdef MyClass
    properties
        name
        value
    end
end
By default, properties are public and can be accessed by using the dot (.) operator.
m = MyClass;
m.name = ‘fun’;
m.value = 0;
Default values of properties can be assigned when they are declared.
classdef MyClass
    properties
        name = ‘fun’;
        value = 0;
    end
end
m = MyClass;
Methods of an object are regular OML functions that can operate on the object’s data. The first parameter to each method is the object itself.
classdef MyClass
    properties
        name
        value
    end
 
    methods
        function obj = AddOne(self)
            obj.value = self.value+1;
            obj.name = self.name;
        end
    end
end

m = MyClass;
m.name = ‘fun’;
m.value = 0;
m = m.AddOne();
The constructor is a special method. It must have the same name as the class itself. The first parameter to the constructor is an exception to the rule above in that it is not the object itself. The constructor is expected to return a newly-created object.
classdef MyClass
    properties
        name
        value
    end
 
    methods
        function obj = MyClass(in_name, in_value)
             obj.name = in_name;
             obj.value = in_value;
        end
    end
end

m = MyClass(‘fun’, 3);
A class can inherit properties and methods from other classes using the < operator.
classdef Employee
    properties
        name;
        ID;
    end
    methods
        function obj = Employee (in_name, in_ID)
            obj.name = in_name;
            obj.ID = in_ID;
        end   
    end
end

classdef Supervisor < Employee
    properties
        group
    end
    methods
        function obj = Supervisor(in_name, in_ID)
            obj.name = in_name;
            obj.id = in_ID;
            obj.group = {};
        end   
    end
end
super = Supervisor(‘Chris’, 4)
In the previous example, instead of duplicating the Employee constructor code in the Supervisor constructor, it is possible to call a method from the base class using the following syntax:
function obj = Supervisor(in_name, in_ID)
            obj = obj@Employee(in_name, in_ID);
            obj.group = {};
        end
A special base class is the handle class. Inheriting from this predefined class allows objects to be treated as references instead of values when passed to functions. In this previous example, it was necessary to return a modified object from the AddOne method and then overwrite the unmodified object with the newly-returned object.
classdef MyClass
    properties
        name
        value
    end
 
    methods
        function obj = AddOne(self)
            obj.value = self.value+1;
            obj.name = self.name;
        end
    end
end

m = MyClass;
m.name = ‘fun’;
m.value = 0;
m = m.AddOne()
Instead, if MyClass inherits from the handle base class, the following code gives the same result:
classdef MyClass < handle
    properties
        name
        value
    end
 
    methods
        function AddOne(self)
            self.value = self.value+1;
        end
    end
end

m = MyClass;
m.name = 'fun';
m.value = 0;
m.AddOne();
m
Standard OML functions can be overloaded in a class’s methods block.
classdef ratnum
    properties
	    n
                  d
	end

	methods
	    function r = ratnum(numerator, denomenator)
		    r.n = numerator;
			r.d = denomenator;
		end

		function r = sqrt(r)
		    r = sqrt(r.n/r.d);
		end
	end
end

a = ratnum(2,3);
sqrt(a)

In this case, when sqrt is called, the class’s method is used instead of the standard built-in function (which is unaware of user-defined classes).

Overloading the disp function has an additional effect. Whenever an object is to be displayed (implicitly or not), the disp method for that object will be called instead of using the standard struct-like display.
classdef ratnum
    properties	    
                  n
                  d
	end

	methods
	    function r = ratnum(numerator, denomenator)
		    r.n = numerator;
		    r.d = denomenator;
                  end

	    function disp(r)
         	        if (r.d ~= 1)
                          fprintf('%d/%d\n', r.n, r.d);
                      else
		 fprintf('%d\n', r.n);
	        end
                  end	
            end
end

a = ratnum(2,3)
Standard OML operators can be overloaded using special method names. For example, if a class contains a method named ‘plus’, this will be called instead of the standard plus function when the operator + is used.
classdef ratnum
    properties	    
                  n
                  d
	end

	methods
	    function r = ratnum(numerator, denomenator)
		    r.n = numerator;
		    r.d = denomenator;
                  end

	    function disp(r)
         	        if (r.d ~= 1)
                          fprintf('%d/%d\n', r.n, r.d);
                      else
		 fprintf('%d\n', r.n);
	        end
                  end	

	    function plus(r1, r2)
	        if (class(r2) == 'ratnum')
	            r = ratnum(r1.n*r2.d + r2.n*r1.d, r1.d * r2.d);
                      elseif (isscalar(r2))
	            r = ratnum(r1.d*r2 + r1.n, r1.d);
	        else
	            r = 0;
	        end                
                end	
            end
end

ratnum(1,3)+ratnum(1,2)
Note: The plus function is called even though it is the + operator that is used.

The first parameter to any overloaded method or operator is guaranteed to be of the specified type, but any additional arguments need to be checked and handled by the class developer. In the previous example, r1 is always a ratnum, but r2 can be a ratnum, a scalar, or anything else (for example, a cell array).

Below is a list of all overloadable operators along with their corresponding method names:
+
plus
-
minus
*
mtimes
.*
times
/
mrdivide
.
rdivide
\
mldivide
.\
ldivide
==
eq
~=
ne
^
mpower
.^
power
uminus
unary minus negates a single object instead of subtracting two objects
Properties can be protected from direct access using an access specifier. This prevents code outside of the class from accessing or modifying these values. Only class methods will be able to do so.
classdef MyClass
    properties (Access = private)
        name
        value
    end
 
    methods
        function obj = MyClass(in_name, in_value)
             obj.name = in_name;
             obj.value = in_value;
        end
    end
end
m = MyClass(‘Ted’, 4)
m.name = ‘Bob’ % this triggers a run-time error