MATLAB: Object Oriented Programming Performance Comparison: Handle Class vs. Value Class vs. no OOP

classMATLABobject oriented programmingoopperformance

I have used Matlab for many years, but have not use the object oriented programming feature until one week ago. The first thing I noticed is that Matlab OOP style is significantly different from other OOP languages such as C++ or java. The next thing I noticed is the significant performance penalty from OOP. In some extreme case, my program slows down by more than 100X, as also reported by other users.
I did several experiments. I feel I find a way to make OOP almost as fast as traditional Matlab program. Both of the observations actually have been pointed out in previous threads. I hope if some expert can confirm this.
The following is summary of my observations.
  • do not call object's method in a loop. Calling the object methods involves a lot of overhead. A bad example is to call the object's method in a for loop.
  • do not use handle class. If it does not mess up your program too much, use value class instead.
Handle class is convenient to use, but it is too slow. Reading or writing object properties, either in object method or from external, it is more than 100X slower in handle class, as shown my test 2 to 4. Something similar to the following is more than 1000X slower in handle class
obj.b = obj.a
It is easy to understand the first one, however I am very curious about the performance difference between handle class and value class. If there is expert in this forum, could you please give some explanation on my observation?
Another question: I need to change the properties of a value class through the its method. It seems that I have to put the object as one of the return parameter, and have to call the method as the following. Is there any better way?
[obj, xout] = obj.method(xin)
Attach one: Experiment Results
Test 1: 100,000 times Method Call
======================================
handle class: Elapsed time is 3.302863 seconds.
value class: Elapsed time is 5.727677 seconds.
no oop: Elapsed time is 0.024743 seconds.
Test 2: 100,000 times Property Internal Access (i.e. in Method)
==============================================
handle class
style 1: Elapsed time is 0.022400 seconds.
style 2: Elapsed time is 0.039167 seconds.
style 3: Elapsed time is 1.780666 seconds.
style 4: Elapsed time is 0.039056 seconds.
no oop: Elapsed time is 0.000502 seconds.
value class
style 1: Elapsed time is 0.000255 seconds.
style 2: Elapsed time is 0.000522 seconds.
style 3: Elapsed time is 0.000242 seconds.
style 4: Elapsed time is 0.000398 seconds.
no oop: Elapsed time is 0.000503 seconds.
Test 3: 100,000 times Properties External Set
==============================================
handle class: Elapsed time is 0.022604 seconds.
value class: Elapsed time is 0.000223 seconds.
no oop: Elapsed time is 0.000189 seconds.
Test 4: 100,000 times Properties External Get
=============================================
handle class: Elapsed time is 0.011324 seconds.
value class: Elapsed time is 0.000221 seconds.
no oop: Elapsed time is 0.000220 seconds.
Attachment two: source code
% no oop function
function a = func_no_oop()
a = 1;
end
% handle class
classdef class_handle < handle
properties
a;
b;
end
methods
function obj = class_handle()
obj.a = 0;
obj.b = 0;
end
function assign(obj)
obj.a = 1;
end
function assignN(obj)
fprintf(1, 'style 1: ');
tic;
for ii = 1:100000
obj.a = 1;
end
toc;
fprintf(1, 'style 2: ');
tic;
for ii = 1:100000
obj.a = obj.a + 1;
end
toc;
fprintf(1, 'style 3: ');
tic;
for ii = 1:100000
obj.b = obj.a;
end
toc;
fprintf(1, 'style 4: ');
tic;
for ii = 1:100000
c = obj.a;
obj.b = c;
end
toc;
fprintf(1, 'no oop: ');
d = 1;
tic
for ii = 1:100000
d = d + 1;
end
toc
end
end
end
% value class
classdef class_value
properties
a;
b;
end
methods
function obj = class_value()
obj.a = 0;
obj.b = 0;
end
function obj = assign(obj)
obj.a = 1;
end
function obj = assignN(obj)
fprintf(1, 'style 1: ');
tic;
for ii = 1:100000
obj.a = 1;
end
toc;
fprintf(1, 'style 2: ');
tic;
for ii = 1:100000
obj.a = obj.a + 1;
end
toc;
fprintf(1, 'style 3: ');
tic;
for ii = 1:100000
obj.b = obj.a;
end
toc;
fprintf(1, 'style 4: ');
tic;
for ii = 1:100000
c = obj.a;
obj.b = c;
end
toc;
fprintf(1, 'no oop: ');
d = 1;
tic
for ii = 1:100000
d = d + 1;
end
toc
end
end
end
%Compare Script
obj_handle = class_handle();
obj_value = class_value();
disp(' ');
disp('Test 1: 100,000 times Method Call');
disp('======================================');
fprintf(1, 'handle class: ');
tic;
for ii = 1: 100000
obj_handle.assign();
end
toc;
fprintf(1, 'value class: ');
tic;
for ii = 1: 100000
obj_value.assign();
end
toc;
fprintf(1, 'no oop: ');
tic;
for ii = 1: 100000
func_no_oop();
end
toc;
disp(' ');
disp('Test 2: 100,000 times Property Internal Access');
disp('==============================================');
disp('handle class' );
obj_handle.assignN();
disp(' ');
disp('value class');
obj_value.assignN();
disp(' ');
disp('Test 3: 100,000 times Properties External Set');
disp('==============================================');
fprintf(1, 'handle class: ');
tic;
for ii = 1: 100000
obj_handle.a = 1;
end
toc;
fprintf(1, 'value class: ');
tic;
for ii = 1: 100000
obj_value.a = 1;
end
toc;
fprintf(1, 'no oop: ');
tic;
for ii = 1: 100000
a = 1;
end
toc;
disp(' ');
disp('Test 4: 100,000 times Properties External Get');
disp('=============================================');
fprintf(1, 'handle class: ');
tic;
for ii = 1: 100000
x = obj_handle.a;
end
toc;
fprintf(1, 'value class: ');
tic;
for ii = 1: 100000
x =obj_value.a;
end
toc;
fprintf(1, 'no oop: ');
tic;
for ii = 1: 100000
x = a;
end
toc;

Best Answer

There is no way to change an object of a value class on method call, other than to return the updated object as a result, and assign it to the variable that held the old object.
This is a strength. One of the core features of MATLAB is its call-by-value semantics: with non-oop MATLAB you can never, for example, accidentally change the value of an array in one part of a program by an assignment to one of its elements in some remote part of the program. Bugs caused by such actions are one of the biggest problems, especially for beginners, in call-by-reference languages. By sticking to call-by-value, MATLAB must have saved countless thousands of hours of debugging time over the years.
However, handle classes break this, which in the context of MATLAB's normal programming model is dangerous. Therefore handle classes should, in my view, only be used when there is an overriding reason. One possible reason is to represent a unique object; another is to implement certain data structures which can only be efficiently updated with handle-class semantics.