How to avoid using a global variable in this case

10 views (last 30 days)
Dear all,
I have the following problem. I wrote some code where I overload various operators (+ - * /) and I would like to keep track of all the operations done. I initialize a session by creating a global variable, "myglobal", which will help me in this endeavor.
global myglobal
myglobal=containers.Map();
Then the typical overloaded operation does the following
function c=plus(a,b)
c=myobject(a.x+b.x);
push(c)
end
where the push function above roughly looks like this
function push(c)
global myglobal
Count=myglobal.Count+1;
myglobal(Count)=c.x;
end
I know using global variables is bad and I would like to get rid of the global variable. Any suggestion on how to go about this?
Thanks,
Pat.
  2 Comments
Walter Roberson
Walter Roberson on 26 Mar 2013
Is the counter to be per-class or per-object ?
Patrick Mboma
Patrick Mboma on 26 Mar 2013
the counter is per object. It is used, among other things, to keep track of the sequence of operations since the container does not order the entries according to their order of occurrence.

Sign in to comment.

Accepted Answer

Jan
Jan on 26 Mar 2013
Edited: Jan on 26 Mar 2013
Use a persistent variable instead:
function Reply = push(c)
persistent myCollector
if isempty(myCollector)
myCollector.Count = 0;
myCollector.Data = cell(1, 1000); % Pre-allocate
end
% Reply the local collector and reset it:
if nargin == 0
myCollector.Data = myCollector.Data(1:myCollector.Count); % Crop
Reply = myCollector;
myCollector = [];
return;
end
count = myCollector.Count+1;
myCollector.Data{count} = c.x;
myCollector.Count = count;
% Re-allocate on demand:
if length(myCollector.Data) == count;
myCollector.Data{count + 1000} = [];
end
end
This reduces the bad effects of letting the data cell grow in each iteration. The data are not stored globally, where any function can overwrite the values accidently. The value of the collector can be checked easily by the debugger in opposite to globals. And you can get the results by:
collector = push();
[EDITED] But when you look at this code, the persistenmt variable is actually a static member of an object oriented approach. When you do some oop already, it would be cleaner to implement this as further object also.
  3 Comments
Jan
Jan on 26 Mar 2013
I have a non-oop (but oo-design) code, which stores a list of "channels" to write text to. A "channel" can be a file, the command window or a GUI-element. Similar to the posted function, I can either manipulate the persistently store list of "channels" or output strings. Instead of using push() you could use a 2nd input to recognize commands to manipulate the collector variable:
function Reply = push(in1, in2)
persistent C
if isempty(C)
% initialize ...
end
% Process meta-commands "push(Command, Data)":
if nargin == 2
switch Command
case 'get'
Reply = C;
case 'reset'
C = [];
case 'append' % Append new values:
C.Data = cat(2, C.Data(1:C.Count), in2, cell(1,1000));
C.Count = C.Count + length(in2);
otherwise
error('Unknown command: %s', in1);
end
return;
end
% Normal processing of "push(x)":
...
end
Then the persistent data are static private data, while there are private functions to access them also.
You see, that the complexity of the function is growing rapidly. And a slightly modified version (perhaps stacks for operations with 1, 2 or 3 arguments) would demand for copying the complete code, such that a later maintenance gets more and more complicated. Therefore I recommend this approach only, if there are reasons to avoid OOP, e.g. backward compatibility.
Patrick Mboma
Patrick Mboma on 26 Mar 2013
Edited: Patrick Mboma on 26 Mar 2013
Thank you very much Jan.
In your implementation, push will then become a static method, instead of public as it is currently the case in my code. While this does not solve all of my problems, but it definitely gets me one step further.

Sign in to comment.

More Answers (1)

Cedric
Cedric on 26 Mar 2013
I thought that you were talking about OOP with your initial question, but if not, it is not a good idea to overload common operators.
A handle class would certainly make everything easier.. e.g.
classdef MBoma < handle
properties
value
history = {}
end
methods
function self = MBoma(value)
self.value = value ;
end
function c = plus(self, b)
if isa(b, 'MBoma')
c = MBoma(self.value + b.value) ;
self.push('plus', b.value) ;
b.push('plus', self.value) ;
else
c = self.value + b ;
self.push('plus', b) ;
end
end
function push(self, id, value)
self.history = [self.history; {id, value}] ;
end
end
end
With that,
>> a = MBoma(5) ;
>> b = MBoma(7) ;
>> c = a + 9
c =
14
>> d = a + b
d = MBoma handle
Properties:
value: 12
history: {}
>> a.history
ans =
'plus' [9]
'plus' [7]
>> b.history
ans =
'plus' [5]
>> d.history
ans =
{}
  1 Comment
Patrick Mboma
Patrick Mboma on 26 Mar 2013
Hi Cedric, I am dealing with OOP, but what I need to keep track of is the sequence of all the operations done, not the operations done by each object.

Sign in to comment.

Categories

Find more on Software Development Tools 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!