when to pass byRef and when to pass byVal - A world apart from the everday ...
Sign in
|
Join
|
Help
Search
A world apart from the everday ...
Assert.IsTrue(Entries.Count == 0);
Home
Contact
About
RSS
Atom
Comments RSS
Recent Posts
Configuration issues with BizTalk Server
Zuma wins ... South Africa LOSES!
BizTalk and "Oslo" ...
When the truth hurts ....
IE8 beta 2 initial thoughts (1 of n)
Tags
Babelog
BizTalk
BizTalk User Group
CRM
Cycleblog
Geekie
IAD
Oslo
Politics
Random Musings
Rant
South Africa
TechEd
Techie
User Group
Navigation
Home
Careers
Downloads
Support
Reading::Blogs
Simon Stewart
Johann de Swardt
Reading::Books
Developing Solutions with Microsoft InfoPath
Microsoft BizTalk Server 2004 Unleashed
Archives
November 2008 (1)
September 2008 (4)
August 2008 (2)
July 2008 (3)
June 2008 (4)
May 2008 (2)
April 2008 (2)
March 2008 (1)
February 2008 (2)
January 2008 (4)
December 2007 (3)
November 2007 (6)
October 2007 (2)
August 2007 (8)
July 2007 (3)
June 2007 (3)
May 2007 (6)
February 2007 (1)
January 2007 (1)
September 2006 (2)
July 2006 (3)
March 2006 (3)
February 2006 (6)
December 2005 (1)
November 2005 (2)
October 2005 (2)
July 2005 (8)
June 2005 (4)
May 2005 (5)
April 2005 (5)
March 2005 (3)
when to pass byRef and when to pass byVal
I realise that you all think this topic has been covered at nauseam in the past but I was horrified recently in an interview when I asked a question at the response I got from a number of so called "senior C# developers". So then I thought I'd check with colleagues, friends, shopkeepers, gardners, pets, in fact everybody hoping and praying to get a decent answer ... surprisingly I got very few correct answers.
So let me now ask the .net development community of SA the following question, and before looking further for the answer and my explanation try and answer this for yourselves. I'd be interested to know your thoughts on this (common i said no cheating!)
What is the output from the following code extract:-
1 using System;
2 namespace ConsoleApplication2
3 {
4 class ByRefByVal
5 {
6 static void Main(string[] args)
7 {
8 Foo f = new Foo();
9 f.SomeString = "initial";
10 Console.WriteLine(f.SomeString);
11
12 DoSomething(f);
13 Console.WriteLine(f.SomeString);
14
15 Console.ReadLine();
16 }
17
18 private static void DoSomething(Foo myfoo)
19 {
20 myfoo.SomeString = "something new";
21 myfoo = null;
22 }
23 }
24
25 class Foo
26 {
27 public Foo() {}
28 public string SomeString=string.Empty;
29 }
30 }
Answer: remember no cheating, you'll thank me for this one day :)
initial
something new
Why Larry, Why? I hear you shout, I passed the foo object into DoSomething byVal why was it changed?
Well did you really pass the foo object into the method call? What really happened here?
We all know the difference between passing value types byval and byref,
If the variable is passed byval any change to the variable value in the called function is not reflected back in the callee because a copy of the variable is passed which is killed upon returning from the called function.
If the value is passed byref it means that the changes will be reflected back because the same variable is passed.
So why did this code produce the result it did?
To answer this we need to take a look at what happens when a reference type is passed by byval.
For ordinary method calls passing a variable as an argument to a method (or property) is logically equivalent to declaring another variable of the same type, and assigning its value to the newly-declared variable.
No surprise, there. For both value- and reference-types, a shallow copy of the variable is made.
For value-types, this means a member-wise copy is created.
For reference-types, only the reference is copied
A Brief Insight into Reference Types:
Data for Reference types is stored on the heap. When creating an instance of a reference type a pointer is created on the stack referencing the memory allocated on the heap to the actual object.
Hence Foo foo = new Foo(); actually returns back the pointer.
Now when this pointer is passed by val a copy of the POINTER is made! This new pointer still points to the same memory on the heap and therfore indirectly to the same object; any changes done to the object in the called method will manipulate the same data to which original foo pointer was pointing.
But notice that when I set foo=null on line 21 nothing happened outside of DoSomething, that's because I never killed the object on the heap, just the myFoo pointer [the byval param of the method] and the original pointer created in the Main method still lives and points happily to the object on the heap.
In case of passing byref, a reference to the original pointer is passed to the called function.
So is there a difference between passing byref and passing byval when dealing with reference types? Yes, but a rather subtle one.
Lets take a look at the slightly modified version of above code:
What do you suppose the output of this code will be?
1 using System;
2 namespace ConsoleApplication2
3 {
4 class ByRefByVal
5 {
6 static void Main(string[] args)
7 {
8 Foo f = new Foo();
9 f.SomeString = "initial";
10 Console.WriteLine(f.SomeString);
11
12 DoSomething(ref f);
13 Console.WriteLine(f.SomeString);
14
15 Console.ReadLine();
16 }
17
18 private static void DoSomething(ref Foo myfoo)
19 {
20 myfoo.SomeString = "something new";
21 myfoo = null;
21 }
22 }
23
24 class Foo
25 {
26 public Foo() {}
27 public string SomeString=string.Empty;
28 }
29 }
Now you can see I'm passing around a reference to a pointer.
If you run the above code it breaks because the calling method attempts to access a null object on line 13.
Why you ask, well by setting myfoo = null on line 21 this time I am actually modiying the original pointer created on line 8,
thereby actually whacking the object from the heap.
Based on this you can see why passing reference types byRef is not a great idea, you have no idea whether or not the called function has disposed of your object for you.
As part of my job I get to do regular code review sessions and something I find ALL the time is DataSet objects being passed all over the place byref, when asking the developer why the response is always
"to stop new copies of the huge dataset being created each time"
.
Sorry to burst your little "performance" bubble fella, but passing a dataset byval
WILL NOT
create a new instance of the object.
You will merely create
a new pointer to the same object
which you are free to do with as you wish.
Of course this begs the question: Can anybody think of a time when you have to pass a reference type by ref?
Share this post:
email it!
|
bookmark it!
|
digg it!
|
reddit!
|
kick it!
|
live it!
Posted:
Nov 08 2005, 04:27 PM
by
Ryan CrawCour
| with
8 comment(s)
Filed under:
Geekie
Comments
Ernst Kuschke
said:
Change the Foo class to a struct, and pass that to DoSomthing by reference, and you'll see the behavior you'd expect ;o)
using System;
namespace DoSomthing
{
class ByRefByVal
{
static void Main(string[] args)
{
Foo f = new Foo();
f.SomeString = "initial";
Console.WriteLine(f.SomeString);
DoSomething(ref f);
Console.WriteLine(f.SomeString);
Console.ReadLine();
}
private static void DoSomething(ref Foo myfoo)
{
myfoo.SomeString = "something new";
}
}
struct Foo
{
public string SomeString;
}
}
Results:
initial
something new
#
November 8, 2005 9:25 PM
Ryan CrawCour
said:
That kinda defeats the object ... changing it to a struct makes Foo a value-type. I was attempting to illustrate what happens when you pass a reference-type by value.
Don't think we could ask MS to change their dataset class to a struct now can we just to get the results we expect.
It is important to know how things work and how to get the expected result the proper way, well at least it is important to some of us :)
#
November 9, 2005 8:15 AM
Simon Stewart
said:
This makes for pretty interesting reading.
I always thought that an object was automatically passed byref and not via the reference copying that you've shown.
I don't know the internal workings of .NET objects well enough to explain why. When Mario L gets round to reading this, I'm sure he'll give a good explanation.
#
November 9, 2005 11:17 AM
Ernst Kuschke
said:
I was illustrating that passing ValueTypes by ref has the effect that some of your guys might expect from RefTypes.
You can't change the behavior of RefTypes. Passing by ref is intended mostly for Value Types in the first place.
Quiz: What's the difference between passing a referencetype by value, and passing a valuetype by reference? :P
#
November 9, 2005 3:29 PM
Ernst Kuschke
said:
Ahhh, now there is the big misunderstanding.
In .NET, reference types are *NOT* passed by reference by default, as is popular belief. A *reference* to the reference type is passed by *value* by default ;o)
#
November 9, 2005 3:32 PM
Senkwe
said:
You asked "Can anybody think of a time when you have to pass a reference type by ref"
I can't think of a good reason off the top of my head. But my first guess is that the presence of the "ref" keyword should act as a clue to callers that you're not dealing with a copy of an object reference, but the reference itself. Now, why someone would do that in the first place isn't clear to me right now
#
November 9, 2005 7:06 PM
malio
said:
Hi Simon
The post is essentially correct,
barring a few technical inaccuracies ... i.e.
['Now you can see I'm passing around a reference to a pointer'] & ['modiying the original pointer created on line 8,
thereby actually whacking the object from the heap.'] &
[a few others])
and some ambigueties ... i.e.
['not the called function has disposed of your object for you.'] &
[a few others])
Objects in C# and VB.Net are passed byval by default. This implies a copy of a reference is made (only the reference! (aka pointer)) or a copy of the value types data (note: only the data is copied, a value type has no instance v-table for dispatch since value types are sealed) before passing.
(go a level deeper and pointers are involved, but it's a topic in itself)
for further clarification I recommend you have a look at:
http://dotnetjunkies.com/WebLog/chris.taylor/archive/2004/06/13/16364.aspx
for some in depth technical info on value types, this is the red pill:
http://blogs.msdn.com/cbrumme/archive/2003/05/10/51425.aspx
And to answer the authours question, ref arguments are needed when wishing to return different instance of reference types (especially useful if the type is immuatble). ie when modifying a string or the invocation list of a delegate. Also required for numerous interop calls.
MaLio
#
November 9, 2005 11:46 PM
Ryan CrawCour
said:
Thanks Mario for the comments.
The links you posted were really helpful thanks a mil!
sorry about the "technical inaccuracies" :$
#
November 10, 2005 10:14 AM
Leave a Comment
Title
(required)
Name
(required)
Your URL
(optional
)
Comments
(required)
Remember Me?
Enter the numbers above: