Can I pass a variable by ref to a function in Matlab?
I want to do something such as this:
function change(x)
x=x+1;
end
and call it like this:
x=1;
change(x)
% x should be 2 now.
The usual style for doing this is to have the same name appear in both the input and output parameter lists:
function [x] = change(x)
x=x+1;
end
x = 1;
x = change(x);
% now 2
For example, the standard function setfield works this way.
In addition, handle objects (e.g. graphic handles) are effectively passed by reference -- the handle numeric value is passed by value, so you can't substitute a different object, but any changes made to the handle object in the function will be visible to the caller.
Since you do not describe your usecase I cannot estimate whether it is worth to define your own handle class but there are situations where you may benefit from the object oriented way.
Your basic example would look something like this:
Define your handle class in a separate file called cnt.m (make sure you inherit from the handle class):
classdef cnt < handle
properties (SetAccess = private)
% a private member variable.
c = 0;
end
methods
function h = cnt(c_init)
% CNT constructs a cnt handle
% CNT()
% CNT(INIT)
if nargin > 0
h.c = c_init;
end
end
function change(h)
% CHANGE increment by one
h.c = h.c+1
end
end
end
Then you can do something like this:
x = cnt();
x.change();
and you can also do something like this:
function change2(cnt_obj)
cnt_obj.change()
and call this function then like so:
change2(x)
which will then do what you are asking for.
The later is the reason why you should inherit from handle. If you create an ordinary value class the call to change2 would create a copy of the actual input object.
Please note that for the simple use case you describe doing something like this is STUPID OVERHEAD. Use this only in case you have good reason to.
Related
I am solving a very large optimization problem. The objective function and constraint function needs numerous data. Currently I am passing the data as a structure to them.
myFS(X, Dat, g_Index, f_Index) % Dat is a structure which includes many variables
Do you think it's an efficient way to reduce the elapsed time?
What better alternatives do exist?
Is this what the given answer, regarding to class definition, means?
%% First we define the class in a separate file:
classdef myDataStructure < handle
properties
NRES;
NOBJ;
NVAR;
end
methods
function obj = myDataStructure()
end
end
end
%% In another file where the main program is, we initialize the class.
Dat = myDataStructure();
%% Initialize
Dat.NRES = 1;
Dat.NOBJ = 1;
Dat.NVAR = 1;
[myF, Dat_updated] = BBB(Dat);
%% Here we define the function and use the class
function [f, CalssDat] = BBB(CalssDat)
x = CalssDat.NRES;
y = CalssDat.NOBJ;
z = CalssDat.NVAR;
f = x + y + z;
CalssDat.NOBJ = 2;
end
As far as I know, MATLAB does not actually copy the content of the data you pass to a function until the point when you modify it in the function itself - in which case it makes a local copy and that takes some CPU time.
Therefore, as long as Dat doesn't change inside myFS(), what you are doing now does not add any CPU overhead. In case you do change the values of Dat inside myFS() and want to return it, I can think of two ways to optimise it:
You can declare myFS() as: function [Dat, anythingElse] = myFs(X,Dat,g_Index, f_Index), which should prevent matlab from making a local copy.
Another approach is to use a class that derives from handle and have Dat be a member of that. This way, whenever you pass the object containing Dat, you only pass the object handle and not a copy of the object itself.
Example of the second approach:
classdef myDataStructure < handle
properties
p1FromDat;
p2FromDat;
% .
% .
% .
pNFromDat;
end
methods
function obj = myDataStructure()
% Add initialization code here if you want. Otherwise p1FromDat
% ... pNFromDat are accessible from outside
end
end
end
Than, in your code:
Dat = myDataStructure();
Dat.p1FromDat = 1;
Dat.p2FromDat = 1;
And in your myFs() you use Dat exactly the same way as you used before.
Because myDataStructure derives from handle, the data inside will not be copied when you pass Dat around.
Do be careful with this, because when you change Dat in myFS(), the values will be changed outside the scope of myFS() as well.
I am working on a GUI in matlab and I'm using a variable called top to store everything. I have an update function that is in one area that updates other areas, but I don't like that it bleeds my topvariable into it, but I can't find a way to just pass the reference to the top variable so that it can still mutate what needs to be mutated.
Is there a pass by reference or some equivalent in matlab?
Edit:
For example I want to move this function to a place where top is inaccessible, but it needs a current top to do it's job, if I were to pass top by reference to the file that makes this I could still access top:
function update_Screens_Callback(~,~)
% Look to see if each check box is marked and if it is add it to seen.
seen = [];
for i=1:10
top.screens{i}.Visible='off';
end
for i=1:4
if(top.sets{i,1}.Value==top.sets{i,1}.Max)
seen = [seen i];
end
end
for i=1:6
if(top.sets{i,2}.Value==top.sets{i,2}.Max)
seen = [seen,i+4];
end
end
tmp = size(seen);
tmp = tmp(2);
sizes = getSizes(tmp);
for i=1:tmp
index = seen(i);
top.screens{index}.Visible = 'on';
top.screens{index}.Position = sizes{i};
end
end
Generally speaking, function calls in MATLAB pass arguments by value, but there is an exception where internal optimization effectively results in passes by reference. When a function returns an argument - e.g. a large matrix - as in
function top = updategui(top)
top(42, 42) = 42;
end
and if you assign the argument as part of the invocation as in x = updategui(x);, MATLAB will recognize that copying top is unnecessary and will pass top by reference.
However, I don't think "passing by reference" will help you solve your specific problem. Much of your question sounds more related to scope than to abstraction or passing by reference vs. by value. For example, it is common practice to share variables across GUI components via setappdata.
Such behavior can be achieved in object oriented matlab. Just create an object as subclass from handle. (Here's some documentation)
classdef myHelper < handle
properties
x
end
end
you can then use it like:
a = myHelper
a.x = important_data
and give a to all your functions.
As example:
a = myHelper
a.x = 1
b = a
b.x = 2
a.x
you will see that a was also updated.
I am a beginner in matlab and learn about the following question online and was having trouble solving it. I have a 1 x 20 matrix called current_load that I need to update periodically. This matrix resides in the main workspace of Matlab (as shown in the code bellow).
current_loads = zeros(1, 20);
for col=1:20
current_loads(1,col)=10; %// Initially give all nodes a current value of 10
end
Object = HandleObject(current_load);%To pass by reference
recursive_remove(Object, 0);
In order to pass current_load by reference, I have created the following class HandleObject.m
classdef HandleObject < handle
properties
Object=[];
end
methods
function obj=HandleObject(receivedObject)
obj.Object=receivedObject;
end
end
end
This matrix will be passed to a function call recursive_remove (shown bellow).
function recursive_remove( current_load, val )
current_load.object = new matrix;
if(val<10)
current_load.object(1,3) = 2+val; %Not the correct way of using current_load ??
end
recursive_remove( current_load, current_load.object (1,3) )
end
Intention here is to modify current_load variable in this function and later I can see these same changes from the main. But This code doesn't work since I don't know how to pass by reference. I need to pass by reference since I am calling this recursively without returning to the main to make it overwrite its variable at the caller. Please show with an example if possible.
If you really need this feature, you can look into turning your HandleObject class into a Singleton like this:
classdef HandleObject < handle
properties
Object=[];
end
methods(Static)
function obj = Instance(receivedObject)
persistent uniqueInstance
try
if isempty(uniqueInstance)
obj = HandleObject(receivedObject);
uniqueInstance = obj;
else
obj = uniqueInstance;
end
catch ME
disp(ME.getReport);
end
end
end
methods
function obj=HandleObject(receivedObject)
obj.Object=receivedObject;
end
end
end
Your recursive function would become a bit simpler then:
function recursive_remove(val )
current_load = HandleObject.Instance();
current_load.object = new matrix;
if(val<10)
current_load.object(1,3) = 2+val;
end
recursive_remove(current_load.object (1,3) )
end
And to create an instance of your HandleObject class, you do something like:
Object = HandleObject.Instance(current_load);
Hope this helps you further.
suppose we have following class,i want to declare rational number class in matlab,i am beginner of object oriented programming in matlab languages and i want to learn basics
classdef ratnum %rational number class
properties (Access=protected)
n %numerator
d %denomerator
end
methods
function r=ratnum(numerator,denomenator)
r.n=numerator;
r.d=denomenator;
end
end
end
how can i create constructor with specific values in matlab main part?should i use name of class ?thanks in advance
To instantiate an object of this class you can use: num1 = ratnum(2,3)
Since MATLAB doesn't have method overloading that is based on the amount of passed inputs, you could use nargin to select the correct scenario, as follows:
classdef ratnum %rational number class
properties (Access=protected)
n %//numerator
d %//denominator
end
methods
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%//whatever you want the defaults to be
end
end
end
end
A simple debug trick is to do num1_str=struct(num1) which allows you to see the contents of the object. However, you should create some public methods to get the values (instead of turning the object to a struct every time).
To overload the default summation of MATLAB you need to understand that whenever you write a+b it is automatically translated into plus(a,b). When defining custom classes with custom summation you should make a folder that has the name #classname (in your case #ratnum) and in it:
ratnum.m: the class definition file (which is the code you wrote)
a file named plus.m which looks something like:
.
function sum = plus(ratnum1,ratnum2)
ratnum1 = ratnum(ratnum1);
ratnum2 = ratnum(ratnum2);
sum = (...
ratnum1.r*ratnum2.d + ...
ratnum2.r*ratnum1.d )/ ...
(ratnum1.d * ratnum2.d);
end
Then, when you use + to add ratnums it will use the correct plus function.
Here's some helpful reading: MATLAB Documntation: Implementing Operators for Your Class
To call class methods, even from within other class methods, you must always write the class name first: ratnum.sum(ratnum1). Here's an example:
classdef ratnum %rational number class
properties (Access=public)
n %//numerator
d %//denominator
end
methods (Access = public)
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%whatever you want the defaults to be
end
end
end
methods (Access = public, Static)
function out = sum(ratnum)
out = ratnum.n + ratnum.d;
end
end
end
then:
>> a = ratnum(1,1)
a =
ratnum with properties:
n: 1
d: 1
>> ratnum.sum(a)
ans =
2
If you want to overload constructor with many different forms you'll have to initialize missing parameters with default value (or use varargin for more complex overloads):
function [r] = ratnum(num, den, varargin)
% Showing initializing missing parameters
if (nargin < 2), den = 42; end
if (nargin < 1), num = 7; end
% Showing working with varargin
if (nargin == 3)
...
elseif((nargin > 1) && (ischar(varargin{1}))
...
else
...
end
end
If you want to create named initializers for clarification of their meaning, you'll have to do it with Static methods:
methods (Static)
function [r] = TwoThird()
r = ratnum(2, 3);
end
function [r] = Half()
r = ratnum(1, 2);
end
end
Which can be used like this:
dummy = ratnum.Half(); % Ratio is 1/2
dummy = ratnum.TwoThird(); % Ratio is 2/3
dummy = ratnum(42, 666); % Ratio can be any custom one
dataset allows us to do:
x = rand(10, 1);
y = rand(10, 1);
d = dataset(x, y);
d will have 2 variables with name 'x' and 'y' and content x and y - variable names are obtained from the workspace. The dataset() call above is equivalent to:
d = dataset({'x', x}, {'y', y});
when the names are specified.
Now if I have a subclass of dataset:
classdef mydataset < dataset
properties
end
methods
function spec = mydataset(varargin)
spec = spec#dataset(varargin{:});
% Add some more things to this subclass because that's the reason I need a subclass
end
end
end
The problem is, if I call:
d = mydataset(x);
d will have the variable x but the name is just 'var1'. The workspace name 'x' is not recognized. Unless I call:
d = mydataset({'x', x});
I will not get the same effect.
Any solution?
Note that I do not want to lose other argument parsing abilities of dataset(). It can process really complicated arguments, and I do want to preserve that.
http://www.mathworks.com/help/toolbox/stats/dataset.html
A = dataset(varspec,'ParamName',Value)
A = dataset('File',filename,'ParamName',Value)
A = dataset('XLSFile',filename,'ParamName',Value)
A = dataset('XPTFile',xptfilename,'ParamName',Value)
The example in this question with mydataset(x) is the a simple and commonly encountered situation that mydataset() can't pass things to dataset() and obtain the same results. Thus it's an important situation. But to do just that and lose other capabilities of dataset() is not worth it.
One option is to capture the argument names yourself and build a cell that you then pass in to the dataset constructor, i.e. you build a cell that looks like
{{Var1 VarName1}, {Var2 VarName2}, ...}
A quick and dirty solution:
classdef mydataset < dataset
properties
end
methods
function self = mydataset(varargin)
for k = 1:nargin
args{k} = {varargin{k}, inputname(k)};
end
self = self#dataset(args{:});
end
end
end
Now if I call it:
>> x=1;
>> y=2;
>> mydataset(x,y)
ans =
x y
1 2
Of course, you've now lost the ability to call mydataset with the {val, valname},... syntax, but maybe that's worth giving up. If you also wanted to be able to do that, you would need to write a conditional that checks the format of your input first, and builds args differently depending on the input format.
Note that you can't do the obvious thing and put your calls to the superclass constructor inside two branches of an if statement. In Matlab, calls to the superclass have to be at the top level (i.e. you can't put them inside loops or conditionals).