Pass variable by reference to function

I have read that the only way to pass by reference with a function is if you pass a handle. Is there a matlab call to get the "handle" of a variable or structure?

 Risposta accettata

While I think IA's answer is the better way to do it. If you really want to do what you are talking about you can create a subclass of handle.
classdef myClass < handle
properties
data
end
methods
function h = myClass(data)
h.data = data ;
end
end
end
Then defining a function (which could be a method) like
function myFunction(h)
h.data = h.data+2;
end
lets you do something like
h = myClass(0);
myFunction(h);
h.data
ans =
2
of course things like h+2 will not work unless you implement a plus method.

4 Commenti

Alessandro
Alessandro il 27 Feb 2013
Modificato: Image Analyst il 27 Feb 2013
Nice post ! Matlab should have something like this as a standard object ! The problem with this class is that it still copy the value from workspace to the class but is a good workaround.
Alternatively, making your variable a global before calling and set your variable as global before updating it in your function.
global variables are not best practice, but this would still work.
Could I ask you why global variables aren't best practice?

Accedi per commentare.

Più risposte (6)

For all practical purposes, you can get the same effect by passing the input argument back out. For example, in the function definition:
function myVariable = ChangeMyVariable(myVariable)
myVariable = 2 * myVariable;
Then to call it, do this:
myVariable = ChangeMyVariable(myVariable);
And, obviously, myVariable could be anything, such as a structure like you mentioned. For all intents and purposes, this is the same as the code you'd use if it were pass by reference:
ChangeMyVariable(myVariable);
The net effect is you get your variable changed, it's just slightly different syntax.

21 Commenti

My goal is to not have to have a return variable yet still be able to modify the input variable and have it stick.
Image Analyst
Image Analyst il 1 Ott 2012
Modificato: Image Analyst il 28 Mag 2014
If you change that goal, you'll be on your way. The ONLY thing you need to add is to add the variable name as an output in the function declaration line, and accept it when you call it. I mean, how much easier can it get? If you don't want to do that, then you can rewrite your code in a different language, but I think that would be a lot harder than adding two words to your MATLAB program.
^I wish I could "like" that comment!
(I wish I could "like" that comment!) ^ 2
An above comment by IA has been flagged by the original poster. I agree with the flag, but I also agree with the original comment. I don't feel comfortable taking unilateral action. Given we do not has a proper set of mod tools nor a meta site I guess this is a reasonable place to discuss it.
The issue as I see it is that the comment in question is not friendly. Therefore the flag is appropriate and the comment should be edited or deleted. The comment is not offensive and adds value so deleting doesn't seem appropriate. Then the question to me becomes should we be editing for tone and not content. This is especially problematic since our editing tools are pretty weak.
I think we need to encourage new users, especially ones who ask good questions like this one. Ignoring/deleting the flag does not seem to be the way to accomplish this. Of course upsetting consistent high quality contributors by deleting their contributions doesn't seem right either.
Q: How do I create the variables A1, A2, A3... A10 in a loop?
A: Doing that is unnecessary and not recommended. You can do this instead
Q: Why are you imposing your opinion as to what is or is not necessary?!?
Matt Fig
Matt Fig il 3 Ott 2012
Modificato: Matt Fig il 3 Ott 2012
Walter's example is more how I took IA's comment. If OP had initially said something like, "I understand that this may be a bad or unnecessary way to go in general, but I am really just curious if this can be done at all," then that would be one thing. I think the tack of pushing folks to use best practices, especially when they are learning the basics, best optimizes the outcome for all. My .02.
This is a resource responded to by volunteers. When you ask a question, you should pretty much expect that an opinion will be given.
I responded to a couple of Questions today and stuck strictly to the facts. The result was that my complete answer to one of the Questions was "Yes.", and my complete answer to the other Question was "No." I could in theory have gone on to say "I think you have asked completely the wrong question, because (appropriate reason)", but, Hey, that would have been "imposing my opinion", and who wants that, right?
I have mentally reviewed the reasons for editing or deleting comments, and I do not perceive any of them apply in this situation: it is, in my judgement, within the bounds of "fair speech" in this context. We have allowed stronger worded comments to stand, when there was no abuse or personal attack.
To me it is not that IA expressed his opinion, but that the response was not as friendly as it could have been.
@Walter, it seems like you are for deleting the flag and leaving the comment untouched.
I would copy the flag content into a Comment for the record, and then delete the flag.
I'm sorry to say that but original reply is wrong! It is not same! For my matlab 2011b on Win calling function with variable and edit that variable do duplicate used memory for that variable (even when stored to same variable). If variable has 1GB then it became a problem when you want just pass reference and modify original variable (Which I do). If I use class <handle it works well and does not duplicate memory consumption.
@Vit's reply resonated with me. I came to MATLAB with decades of software engineering experience in other languages. Passing by value or by reference was (is) an important consideration in some languages. @Vit mentioned that his program "duplicate used memory for that variable". I just did a quick test by creating a function that modified 1 element of a 1M element matrix. I toggled the assignment in the function by commenting it out. Memory decremented by ~8 MB when X(1) was changed, and not when X was not changed. /This/ is the reason that I and others have asked about passing by reference. The snippy comment by AI in 2012 didn't address this. It may have addressed the effect, but not the concern of the OP. I shouldn't have had to write a test just to fully understand what MATLAB does. This simple example should be a part of the docs, along with a clear statement that the entire passed matrix is duplicated when 1 element is changed.
M = (1.0: 1.0: 1000000);
memory
M = Passing_by_reference_or_value_test_0100_function (M);
M (1)
memory
function X = Passing_by_reference_or_value_test_0100_function (X)
X (1) = 2.0;
X (1)
memory
end
MATLAB docs mention "smart" passing, but if passing by reference were allowed in the first place, there would be less confusion, and no need for discussions of "smart" updating of the calling variable space, nor would MATLAB need to keep track of what changed. If I passed a matrix in, say, Pascal, by reference, then modified X(1), there would be no question of how much memory was used, where the variable existed, or what was changed in the matrix. What is not clear to me is how MATLAB handles a situation where I pass in a matrix, make local changes to some elements, and /don't/ pass the matrix back to the calling frame. Does MATLAB make only local copies of the elements that changed? In that case, there is a trade-off: MATLAB bookkeeping overhead versus copying the entire matrix, which can involve putting it on a stack and popping it off a stack, both memory intensive, not to mention copying a 1 million-element matrix, and changing only a small percentage of elements. It seems from my test above that MATLAB does, indeed, make a full copy of the passed matrix. Creating a subclass of handle seems to me a wordy and inefficient alternative to simply providing pointers to variables AND|OR a "pass by reference" keyword in the function formal parm list. ~R~
James Tursa
James Tursa il 27 Mag 2014
Modificato: James Tursa il 27 Mag 2014
To get the in-place memory savings to happen automatically for your example, I think the rules are you have to make the call from within another function. Otherwise, you will get the temporary double memory impact. Did you make the call from the command line?
In general, if you want in-place behavior regardless of how you call things or when/where you modify them, then you either need to derive a class from handle, or do the work in a mex routine using unofficial means.
"What is not clear to me is how MATLAB handles a situation where I pass in a matrix, make local changes to some elements, and /don't/ pass the matrix back to the calling frame. Does MATLAB make only local copies of the elements that changed?"_ _
No. if you change only 1 element of a 1GB array, MATLAB will suddenly make a 1GB deep data copy of the array first, then change the 1 element. This is the general behavior of shared data copy variables that do not derive from handle and are not part of the special in-place function syntax and calling rules noted above.
I still believe the net effect, when you're not worried about running out of memory, is the same. I agree that, sure, it might do it differently, and might cause you to run out of memory for really huge arrays, and it might take longer , but for most ordinary situations your output variable will still get changed into the same value and you won't notice the difference. Again, for ordinary situations, not memory hog situations. So I don't agree that my "original reply is wrong!" I also agree that pass by reference might have some situations where it's preferable to use that method.
I want to thank both IA and ninetrees for their contributions, which have made a lot clear. Personally, absence of even the possibility (e.g. using a simple flag) of Pass-By-Reference is mind-boggling! IA offers a workaround, but copying the full array is unacceptable because milliseconds matter. When is this fixed?
Hi Lucas,
the programming pattern that Image Analyst showed, namely
function Y = someFun(x, Y, z)
Y = x + Y;
involves no copying of Y at all, provided, that you
  • call it like var = someFun(x, var, y), i.e. both the function declaration and the calling function use the same variable names for input and output
  • Your MATLAB version is not too old: this optimization was introduced somewhere around 2010.
Give it a try with a large variable. You will see in the task manager no copy is done.
Titus
Hi, I tried your trick with very large matrix. By the jump in the memory consumption I can assure you it is not working by reference.
I think there is a typo in the comment by Titus Edelhofer, it should read
var = someFun(x, var, y),
rather than
var = someFun(x, Var, y),
@Royi, Which release are you running?
> For all practical purposes,
I think it's worth noting that timer function is one non-trivial practical application where if output of the callback function is intended to be used, it needs to modify input variable as a reference instead.
By default, timer objects receive only a copy of the timer object (as the first parameter), and a bit of state information (Type: 'TimerFcn', 'Data', datevec(now)) . There is no meaningful input variable to change.
You can use "parameterization" to capture a variable into an anonymous function and pass the captured variable into the timerfcn; this approach is not uncommon at all.
However... once a variable is captured, modifying the variable at most modifies the local copy of it
captured_variable = 5;
f = @() try_capture(captured_variable)
f = function_handle with value:
@()try_capture(captured_variable)
captured_variable = 1
captured_variable = 1
f()
5
captured_variable
captured_variable = 1
f()
5
captured_variable
captured_variable = 1
function try_capture(captured_variable)
disp(captured_variable)
captured_variable = 7;
end
You propose that such captured variables become modifiable pointers... but what would be modified? In the above example, after f executes the first time, should captured_variable become 7, even though it has been redefined since the time it was captured?

Accedi per commentare.

per isakson
per isakson il 28 Set 2012
Modificato: per isakson il 28 Set 2012
No, there is no way to pass a variable by reference. See Memory Management for Functions and Variables.

2 Commenti

I understand that only handles can be passed by reference. Is there a way of obtaining a handle for a variable?
per isakson
per isakson il 28 Set 2012
Modificato: per isakson il 28 Set 2012
No, not with documented Matlab. And not with http://undocumentedmatlab.com/ as far as I know.
Why do you want to pass by reference?

Accedi per commentare.

James Tursa
James Tursa il 29 Set 2012
I will ask again what others have already asked. Why do you want the "handle" to the variable? What advice we give you will depend on the answer to that question. FYI, by default MATLAB passes a shared data copy of the arguments to the function ... i.e., there is no data copy involved. So it is already efficient in that sense. But we really need to know what you are doing with the variable inside the function in order to best answer your question, and whether passing by "reference" makes sense for your application.

9 Commenti

This isn't a memory question as much a code cleanliness, reuse, and good practices question as well as my own edification. I'm not looking for coding advice, but an answer to the question of if it is fundamentally possible to get the "handle" of a variable or structure?
If it is a question about code cleanliness, reuse, and good practices, then you are looking for coding advice, and IA's recommendation to use a return value is not "imposed" is an appropriate "good practices" response. Hidden modification of variables is not good practice; it is, for example, emphatically disallowed in Yourdon & Constantine's "Structured Design" (1979)
Using pointers is not a hidden modification of a variable. It's a efficient practice widely used in any performing language.
Once you pass in a pointer, you lose control over whether there is a modification to the original data or not. You cannot tell from a C function declaration whether it modifies the data stored at any given pointer: at best you can hope that the person who wrote the function was diligent about putting in "const" where-ever possible.
Some languages require that every parameter to a function be marked as either input only, output only, or in/out . With such languages, there is never any surprise factor. If your goal is code cleanliness, reuse, and good practices, then you should prefer to avoid languages where the default is to permit modification of any item you have a pointer to.
I don't understand this point. If const is not used in C and C++ code for pointers passed to a function, then you should assume that the function is going to modify the data. That is what should be expected when you read such a function signature, and you can't go wrong if you make that assumption. Copy your data before passing it if you don't want your data modified and there will be no "surprises."
Also, const is more powerful that just for function signatures, it can be used to guaranty that methods of objects do not modify their member data. Code that does not obey const correctness is one of the quickest ways to determine whether or not it is code worth using.
There may be several reasons to choose other languages over C and C++, but I would argue that clarity over whether or not a function will modify datastructures passed to it is not one of them.
Most C code does not use const in function signatures, because traditionally it was considered unnecessary: the code could simply refrain from modifying the data.
For all that C++ looks like an exercise in trolling to see how far you can bend a good idea before users rebel, I have to admit the the culture of C++ programming has been pretty good in using "const" where practical.
Thanks, good point about legacy C code. The reality though is that C shouldn't be used for programming beyond low level stuff like kernels and drivers. The C programming community typically subscribes to this point of view (as I recall the #C freenode IRC channel had a statement to that effect in their channel description). I know Linux Torvalds doesn't like C++, but the reality is that if you use it right and don't try to use extended features that tend to make your code obfuscated, it keeps you from shooting yourself in the foot, particularly with respect to memory management. I wouldn't touch a piece of code that didn't subscribe to proper const correctness. Having said all that, I have recently used Darknet, a deep neural network framework written in C which was refreshingly stripped down and extremely portable because it didn't have any dependencies besides CUDA. Ultimately, that implementation is just too dangerous to use in production, and not flexible enough for all environments (like CPU deployment).
Uh, No, the C community does not typically believe that C should only be used for low-level things like kernels and drivers!
I started programming in C in the early 1980s, and I hung around in the C Usenet programming groups for... Must have been over 25 years, starting even before The Great Renaming (of Usenet), from before C was standardized, before C++ was invented. C continues to be considered a "live" language for general use.
I also spent a good amount of time programming in C. Not quite as far back. Through most of the 90s, later switched to C++, and spent time reverse engineering Objective C and C as part of the iOS jailbreak dev community in the late 2000s. I spent a lot of time hanging out in IRC channels including #C and ##C, and as I mentioned, their mission statement basically renounced C as an application programming language. I think most good C programmers--who are also not blindly religious about the language--are honest about there almost always being a better choice than C for application programming. There just isn't a rich enough standard library--nor well used enough third party library--for writing programs as quickly or stably as they can be written in C++. C is small and as such is best suited for the types of programs that must have small footprints. The standard library plus RAII in C++ means that you can write an entire major C++ application without every having to call new, delete, malloc, or free yourself, and pay basically no penalty. And if you do have to call new/delete, you can put it into a very lightweight container like unique_ptr and continue to have exception safety. In short, I think it would be hard to argue that building an application in C is better than building it in C++, other than for environments where optimizing footprint is paramount. And, nothing stops you from using a C library where needed in a C++ program. Heck, even compiling C code with a C++ compiler (which is more strict) would likely uncover hidden issues in your C code.

Accedi per commentare.

Hello I would say a possible solution is the following (without using classes):
%Reference to some matlab Data
function reference = globaldata()
data = [];
reference = struct('GET',@GET,'SET',@SET);
function dataout = GET()
dataout = data;
end
function SET(datain)
data =datain;
end
end
I saw something like this for making linked lists in matlab on stack overflow.
This isn't so much an answer but an example of why pass-by-reference would be useful. I want to pull an array of values out of an ode45 OutputFnc, the straightforward programming way to do this would be to create a closure over a local variable which was passed along with the function handle into ODE45 and have the OutputFnc update that. Since the original program is not the caller of the OutputFnc -- ode45 is -- it is not possible to use the output parameters.
T0a = [];
options = odeset('OutputFcn', @(t, y, flag) odethrust(t, y, flag, T0a, mf_bar, thrust_bar));
[t, y] = ode45(@(t, y) ode(t, y, tf0/2, thrust_bar, mf_bar, ve_bar), lgt, y0, options);
T0a
function dXdtau = ode(t, y, tau, thrust_bar, mf_bar, ve_bar)
r = y(1);
v = y(2);
m = y(3);
if m < mf_bar
T = 0;
else
T = thrust_bar;
end
drdt = v;
dvdt = - 1/r^2 + T / m;
dmdt = - T / ve_bar;
dXdtau = tau * [ drdt dvdt dmdt ]';
end
function status = odethrust(t,y,flag,T, mf_bar, thrust_bar)
if isempty(flag)
m = y(3);
if m < mf_bar
T = [ T 0 ];
else
T = [ T thrust_bar ];
end
end
status = 0;
end
That is a snippet out of a real program so some variables like mf_bar/ve_bar/thrust_bar/etc aren't declared. The structure of the ODE isn't terribly important other than I'm trying to access the time history of the T variable as well as the variables of integration (pretend that the simplistic way T is handled now could be arbitrarily complicated so I don't want answers that figure out the problem analytically outside of this loop -- if you can guess the problem domain, you can be sure I know that the rocket equation exists).
The important point is the way that I want to declare T0a as an empty array, and then pass that into the function handle of odethrust, which is the OutputFcn for the ode45 call.
I guarantee there's nothing wrong -- in a computer science sense -- with wanting to pass in a closure like this to accumulate state.
Bart McCoy
Bart McCoy il 7 Dic 2021
Modificato: Bart McCoy il 7 Dic 2021
I've been using Handle classes for awhile now and they are as close to "pass by reference" as you can get in MATLAB. Whether it's truly "pass by reference" or not may be an academic debate because it looks & acts like a duck & acts like a duck, so....
When you create an instance of a handle class, you can still create many distinct, independent instances. But for each instance you create, there is only one copy of that instance, no matter how many times you store it, pass it into other objects where they store it, etc. When you change it in one location, it's changed in ALL locations because there is only one copy of that instance.
Some practical benefits:
  1. With a class method, you can modify an object's contents & you no longer have to return the object. No danger of stale objects.
  2. Once you create an instance & store it somewhere (inside other objects, structs, object arrays, etc), the instance exists until ALL reference to your instance are gone or until you run delete(instanceName)
  3. If your object stores lots of data, a handle class won't keep copying your data & bloating memory useage
  4. If you need to share an object/data with lots of items, such as a global settings or a common configuration, or if you have communication/messaging/flag variables shared between lots of objects, handle classes are a dream!! Create one instance and share it with all your objects & let them store it for their lifetime. Whenever some object's code/class/function updates the single instance, all objects instantly see the same updates.
Handle classes might be a bad idea if you want objects to be fluid & copied in math operations, using overloaded operators for math-like operations.... where you're expecting implicit copies of the object (in a right-hand side set of math operations) to act independently, but they are really the same object.
To make your custom class a "handle class", you simply change the first line in the class from:
% Normal, non-handle class; An object instance is pass by value; the
% instance (and all data within it) is copied everywhere
classdef myClass
% bla bla bla
end
% Handle class; An object instance acts like pass-by-reference;
% For each instance, there is only one copy; change it once and it changes
% everywhere
classdef myClass < handle
% bla bla bla
end
% EXAMPLE CLASS AND SOME TESTS I WROTE TO HELP CLARIFY
% Save as InventoryHC.m
classdef InventoryHC < handle
properties
apples = 0;
bananas = 0;
total = 0;
end
methods
function obj = InventoryHC()
end
function computeTotal(obj)
obj.total = obj.apples + obj.bananas;
end
end
end
% TEST CODE TO HELP UNDERSTAND HOW HANDLE CLASS WORKS
clear all; clc;
% ONE instance of a handle class
inv1 = InventoryHC();
inv1.apples = 20;
inv1.bananas = 30;
inv1
inv1.computeTotal(); % NOTICE!! The object changed and you didn't have to return the object!
inv1
% ANOTHER independent instance of a handle class
inv2 = InventoryHC();
inv2.apples = 100;
inv2.bananas = 300;
inv2.computeTotal(); % NOTICE!! The object changed and you didn't have to return the object!
inv2
inv1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Make copies of the instance "inv1" and show that
% changing them in one location changes them everywhere
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Assign instance "inv" to another varible
newInv = inv1;
% Create a structure and store the object in it
dataset1 = struct();
dataset1.A = inv1;
dataset1.B = newInv;
invArray = [ inv1 newInv ]; % Create an object array & store the instances in it
invCell = { inv1 newInv }; % Create a cell array & store the object instances
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now change the original instance in one place and show that
% it changed EVERYWHERE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
inv1 % Before we change it
inv1.apples = -5; % Make changes
inv1.bananas = -6;
inv1.computeTotal();
inv1 % View changes to the original instance
newInv % View the copy of the instance (it's also been changed)
dataset1.A % Instances stored in the structure (it's also been changed)
dataset1.B
invArray(1) % Instances in the object array (they've been changed, too)
invArray(2)
invCell{1} % Instances in the cell array (they've been changed, too)
invCell{2}
clear inv1; % Clear the original var; it's not special; it has a reference to the instance, just like the structure, array & cell array
newInv % Object is still alive & well
dataset1.A % Object is still alive & well
clear newInv dataset1 % Clear the other var and the structure
invArray(1) % The same object still persists; it will continue to persist until:
% a) all references to it are gone so it can garbage collect
% -OR- b) you call delete() to explicitly delete it
isvalid(invArray(2)) % Show that we still have a valid handle
delete(invArray(2)); % Delete the 2nd element in the array... this wipes out the instance EVERYWHERE
isvalid(invArray(2)) % Show that the handle is no longer valid
invArray(1) % Now just have an empty handle... no object assigned to it anymore
invArray(2) % Now just have an empty handle... no object assigned to it anymore
invCell{1} % Now just have an empty handle... no object assigned to it anymore
invCell{2} % Now just have an empty handle... no object assigned to it anymore
inv2 % This is a distinct instance created by it's own constructor call, so it's not tied to inv1

Categorie

Scopri di più su Programming in Centro assistenza e File Exchange

Prodotti

Richiesto:

il 28 Set 2012

Commentato:

il 11 Feb 2025

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by