When Passing Objects as Parameters, Are They Passed by Reference

Passing Objects By Reference or Value in C#

Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.

If you want to use pass-by-reference, you must use out or ref, whether the parameter type is a value type or a reference type. In that case, effectively the variable itself is passed by reference, so the parameter uses the same storage location as the argument - and changes to the parameter itself are seen by the caller.

So:

public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}

public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}

public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}

I have an article which goes into a lot more detail in this. Basically, "pass by reference" doesn't mean what you think it means.

Why are objects automatically passed by reference?

Why are objects automatically passed by reference?

They're not.

Is there any particular benefit from forcing the cloning process for them instead of treating objects more like int, double, boolean, etc. in these cases?

There's no "cloning process" for reference types, only for value types.

I think you're confusing different concepts:

  • value types vs. reference types

    For value types (such as primitive numeric types, enums, and structures like DateTime), the value of the variable is the object itself. Assigning the variable to another (or passing it as a parameter by value) creates a copy of the object.

    For reference types (such as object, string, classes (not structs) etc), the value of the variable is a reference to the object. Assigning the variable to another (or passing it as a parameter by value) creates a copy of the reference, so it still refers to the same object instance.

  • passing parameters by value vs. by reference

    Passing parameters by value means that you pass a copy of the value. Depending on whether it's a value type or reference types, that means a copy of the object itself, or a copy of the reference. If the callee modifies members of a value type passed as a parameter, the caller won't see the changes, since the callee is working on a copy. On the other hand, if the callee modifies members of a reference type passed as a parameter, the caller will see the changes, because the callee and caller both have a reference to the same object instance.

    Passing parameters by reference means that you pass a reference to a variable (which may be a variable of value type or reference type). The value is not copied: it is shared between the caller and the callee. So any change made by the callee (including assignment of a new value to the parameter) will be seen by the caller.

    Unless specified otherwise (with the ref or out keywords), all parameters are passed by value, including reference types. It's just that for reference types, the value that is passed is a reference, but it's still passed by value.

I suggest you read Jon Skeet's article Parameter passing in C# for a better explanation.

Does C++ pass objects by value or reference?

Arguments are passed by value, unless the function signature specifies otherwise:

  • in void foo(type arg), arg is passed by value regardless of whether type is a simple type, a pointer type or a class type,
  • in void foo(type& arg), arg is passed by reference.

In case of arrays, the value that is passed is a pointer to the first element of the array. If you know the size of the array at compile time, you can pass an array by reference as well: void foo(type (&arg)[10]).

When passing objects as parameters, are they passed by reference?

Yes

Both method calls will take about the same amount of time.

(It's good to be aware of performance consequences and you asked a reasonable question, but even so, the standard disclaimer1 about early optimization technically applies.)


1.
First, make program work.
Then, profile.
Finally, and maybe, optimize.
Donald Knuth said:
We should forget about small
efficiencies, say about 97% of the
time: premature optimization is the
root of all evil.

Passing objects by reference vs value

What I don't understand is what happens when I invoke a method, what actually happens. Does new() get invoked? Does it just automagically copy the data? Or does it actually just point to the original object? And how does using ref and out affect this?

The short answer:

The empty constructor will not be called automatically, and it actually just points to the original object.

using ref and out does not affect this.

The long answer:

I think it would be easier to understand how C# handles passing arguments to a function.

Actually everything is being passed by value
Really?! Everything by value?
Yes! Everything!

Of course there must be some kind of a difference between passing classes and simple typed objects, such as an Integer, otherwise, it would be a huge step back performance wise.

Well the thing is, that behind the scenes when you pass a class instance of an object to a function, what is really being passed to the function is the pointer to the class. the pointer, of course, can be passed by value without causing performance issues.

Actually, everything is being passed by value; it's just that when
you're "passing an object", you're actually passing a reference to that
object (and you're passing that reference by value).

once we are in the function, given the argument pointer, we can relate to the object passed by reference.

You don't actually need to do anything for this, you can relate directly to the instance passed as the argument (as said before, this whole process is being done behind the scenes).

After understanding this, you probably understand that the empty constructor will not be called automatically, and it actually just points to the original object.


EDITED:

As to the out and ref, they allow functions to change the value of an arguments and have that change persist outside of the scope of the function.

In a nutshell, using the ref keyword for value types will act as follows:

int i = 42;
foo(ref i);

will translate in c++ to:

int i = 42;    
int* ptrI = &i;
foo(ptrI)

while omitting the ref will simply translate to:

int i = 42;
foo(i)

using those keywords for reference type objects, will allow you to reallocate memory to the passed argument, and make the reallocation persist outside of the scope of the function (for more details please refer to the MSDN page)

Side note:

The difference between ref and out is that out makes sure that the called function must assign a value to the out argument, while ref does not have this restriction, and then you should handle it by assigning some default value yourself, thus, ref Implies the the initial value of the argument is important to the function and might affect it's behaviour.

What exactly does pass by reference mean?

Sure, different people currently have different definitions of what "pass-by-reference" means. And that is why they disagree on whether something is pass-by-reference or not.

However, whatever definition you use, you must use it consistently across languages. You can't say that one language has pass-by-value, and have the exact same semantics in another language and say that it is pass-by-reference. Pointing out the analogies between languages is the best way to address this dispute, because although people might have strong opinions about the passing modes in particular languages, when you contrast the identical semantics with other languages, it sometimes brings counter-intuitive results that force them to re-think their definition.

  • One predominant view is that Java is pass-by-value only. (Search everywhere on the Internet and you will find this point of view.) This view is that objects are not values, but are always manipulated through references, and thus it is references that are assigned or passed, by value. This view holds that the test of pass-by-reference is whether it is possible to assign to a variable in the calling scope.

If one agrees with this viewpoint, then one must also consider most languages, including as diverse ones as Python, Ruby, OCaml, Scheme, Smalltalk, SML, Go, JavaScript, Objective-C, etc. as pass-by-value only. If any of this strikes you as strange or counterintuitive, I challenge you to point out why you think it is different between the semantics of objects in any of those languages from objects in Java. (I know that the some of these languages may explicitly claim that they are pass-by-reference; but it is irrelevant what they say; a consistent definition must be applied to all languages based on the actual behavior.)

  • If you take the opposing view that objects in Java are pass-by-reference, then you must also consider C as pass-by-reference.

Take your Java example:

class Thing { int x; }
void func(Thing object){ object.x = 42; object = null; }
Thing something = null;
something = new Thing();
func(something);

in C, it would be equivalent to this:

typedef struct { int x; } Thing;
void func(Thing *object){ object->x = 42; object = NULL; }
Thing *something = NULL;
something = malloc(sizeof Thing);
memset(something, 0, sizeof(something));
func(something);
// later:
free(something);

I claim that the above are semantically equivalent; only the syntax is different. The only syntax differences are:

  1. C requires an explicit * to denote a pointer type; Java's reference (pointers to objects) types don't need an explicit *.
  2. C uses -> to access a field through a pointer; Java just uses .
  3. Java uses new to dynamically allocate memory for a new object on the heap; C uses malloc to allocate it, and then we need to initialize the memory.
  4. Java has garbage collection

Note that, importantly,

  1. The syntax for calling the function with the object are the same in both cases: func(something), without needing to do anything like taking address or anything.
  2. In both cases, the object is dynamically-allocated (it may live beyond the scope of the function). And
  3. In both cases, the object = null; inside the function does not affect the calling scope.

So the semantics are the same in both cases, so if you call Java pass-by-reference you must call C pass-by-reference too.

Object passed as parameter to another class, by value or reference?

Objects will be passed by reference irrespective of within methods of same class or another class. Here is a modified version of same sample code to help you understand. The value will be changed to 'xyz.'

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
public class Employee
{
public string Name { get; set; }
}

public class MyClass
{
public Employee EmpObj;

public void SetObject(Employee obj)
{
EmpObj = obj;
}
}

public class Program
{
static void Main(string[] args)
{
Employee someTestObj = new Employee();
someTestObj.Name = "ABC";

MyClass cls = new MyClass();
cls.SetObject(someTestObj);

Console.WriteLine("Changing Emp Name To xyz");
someTestObj.Name = "xyz";

Console.WriteLine("Accessing Assigned Emp Name");
Console.WriteLine(cls.EmpObj.Name);

Console.ReadLine();
}
}
}

Java pass by reference

Java always passes arguments by value NOT by reference.


Let me explain this through an example:

public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will modify the object that the reference variable "f" refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}

I will explain this in steps:

  1. Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

    Foo f = new Foo("f");

    Sample Image

  2. From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

    public static void changeReference(Foo a)

    Sample Image

  3. As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

    changeReference(f);

    Sample Image

  4. Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

    Foo b = new Foo("b");

    Sample Image

  5. a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".

    Sample Image


  6. As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

    Sample Image

  7. c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

    Sample Image

I hope you understand now how passing objects as arguments works in Java :)



Related Topics



Leave a reply



Submit