How the 'ref' keyword affects the use of objects
This is something that doesn't make any sense until you've stepped through it carefully. And it's something that i didn't understand correctly (or hardly think about) when I was programming in VB.net. What exact difference does a ref keyword make, when applied to a class-type parameter, anyway? [VB Note: substitute the keyword ref for ByRef, and know that a C# parameter without a ref keyword is considered ByVal by default. So the sentence above could read: "What exact difference does a ByRef keyword make, when applied to a parameter that is a class-type?"] First up, a re-cap of how 'ref' affects simpler variable types.... (continues...lots of code examples!)
Imagine we have a little function like this:
private void TryAndChangeTheValue(string name)
{
name = "Ziggy Stardust";
}
And we call it with some code like this:
string Name = "Jimi Hendrix";
TryAndChangeTheValue(Name);
MessageBox.Show(Name);
What happens? Does it return 'Jimi Hendrix' or 'Ziggy Stardust'?
It shows 'Jimi Hendrix'. Because the parameter does not have the 'ref' keyword, a copy of the value 'Name' is created, altered and then not returned from the stack. So the initial value of 'Name' is displayed in the messagebox.
If you want the function to affect the displayed message, you need to use the ref keyword, as follows:
private void TryAndChangeTheValue(ref string name)
{
name = "Ziggy Stardust";
}
And you need to add the keyword ref to your calling code:
Now when the above code is run, the value 'Ziggy Stardust' will be displayed.
Okay, recap over. Time to think about classes.
But what happens when you do (or don't) use the ref keyword on an object parameter?
Imagine we have a simple little class like this:
private class NameClass
{
public string Value = "Jimi Hendrix";
}
It has one public field, 'Value' which defaults to 'Jimi Hendrix'.
And now imagine we have a function that looks like this:
private void TryAndChangeTheValue(NameClass name)
{
name.Value = "Ziggy Stardust";
}
It accepts a 'NameClass' object, and changes the name property to 'Ziggy Stardust'.
Now what happens when we call the method, and then check the value...
NameClass name = new NameClass();
TryAndChangeTheValue(name);
MessageBox.Show(name.Value);
Will the messagebox show 'Jimi Hendrix' or 'Ziggy Stardust'?
Before you answer, consider this case:
What if we changed the function to look like this:
private void TryAndChangeTheValue(ref NameClass name)
{
name.Value = "Ziggy Stardust";
}
So that now the parameter is of type reference. (We'll also need to add the 'ref' keyword to our calling code)
NameClass name = new NameClass();
TryAndChangeTheValue(ref name);
MessageBox.Show(name.Value);
Will the 'ref' keyword make any difference to our test? If so, why? If not, why not?
For both these tests, the result will be 'Ziggy Stardust'. The ref keyword won't make a difference to the results.
Does that mean that the ref keyword was ignored? Not at all.
The important thing is that the ref keyword applies to the parameter (name), not to its properties (name.Value).
So let's look at a case where the function doesn't just change a property of the parameters, but tries to change the parameter itself. In that cases the ref parameter will make an important difference.
Here's an example where our function gets sloppy and drops the object.
private void TryAndChangeTheValue(NameClass name)
{
name.Value = "Ziggy Stardust";
name = null;
}
What will happen now?
Will this code:
NameClass name = new NameClass();
TryAndChangeTheValue(name);
MessageBox.Show(name.Value);
Still return 'Ziggy Stardust?' Or will we get a null reference exception?
We will still get 'Ziggy Stardust' out. There won't be a null reference exception, because the thing that was set to null was a value copy of the object reference, not a direct reference to the object.
The object itself wasn't affected by the 'name = null' line. That merely stopped a value on the stack from pointing to the object.
And then consider the same code, but with the 'ref' keyword:
private void TryAndChangeTheValue(ref NameClass name)
{
name.Value = "Ziggy Stardust";
name = null;
}
What will happen when this code is used to call it?
NameClass name = new NameClass();
TryAndChangeTheValue(ref name);
MessageBox.Show(name.Value);
Will we get a 'ziggy stardust'? Or a null reference exception?
In this case we get a null reference exception. Because now when the name = null line was executed, it was the reference itself that was set to null, not just a copy of it on the stack.
Okay that's all i want to say about that.
Mistakes A-Plenty
Please feel free to point out any mistakes in this article, i'm sure there are plenty. ;-)
(Miss Takesa Plenty sounds like a femme fatale from a James Bond novel... just thought i'd mention it...)
'Douglas Stockwell' on Fri, 23 Jun 2006 13:41:50 GMT, sez: Mistakes? Indeed. string is not a value type.
'lb' on Sat, 24 Jun 2006 00:59:38 GMT, sez: indeed. string was a poor choice. originally i had an "Age" class and an "increment" function.... in that case we were using real 'value' types as the non-class type.
so i changed the wording a little to just skate around this issue.
cheers.
'Matthew' on Sun, 25 Jun 2006 21:28:45 GMT, sez: It scares me that people don't understand this. Hell - VB 6 worked the same way...
'lb' on Sun, 25 Jun 2006 21:53:33 GMT, sez: generally if you never think about it, it never troubles you.
but what i saw lately was use of the 'ref' keyword, when it wasn't needed (because properites of an object are being altered, but not the object itself). the justification was that it would 'save memory' because otherwise 'a copy of the object would be created'.
this troubled me enough that i wrote it up.
'MB' on Thu, 29 Jun 2006 13:13:44 GMT, sez: I sometimes use ByRef to indicate that the called function will change the parameter...even if it doesn't change the reference.
Then again, I don't do it consistently, so I should probably just stop doing it at all....
'Laboremus' on Thu, 29 Jun 2006 15:42:35 GMT, sez: lb - I would vote for using or not sing "ref" purely from position of readability. If you mean to make a change in the original object - put explicit "ref". Eventually somebody could change a method hoping that changes will stick.
Because Jedi who wrote The Code will be followed by mortals, who will be supposed to support it.
'jokiz' on Fri, 30 Jun 2006 09:40:11 GMT, sez: i disagree, having a reference type passed by ref is somewhat unsafe for me if what you really care is to change some of the object's property which can be done by pass by value. you're just giving the method full access to the object instance, which he can redirect to another.
'PeterNZ' on Tue, 04 Jul 2006 00:06:44 GMT, sez: Agree! ref or ByRef is not a comment which improves readbility! It has an impact on lots of things!
'Harish Prabhakar ' on Tue, 04 Jul 2006 03:06:55 GMT, sez: i would suggest to go for a return type of that class....instead of using ref keyword, n i say this purely on readability point of view. cos very seldom happens tht a code written by me is reviewd by myself ;)
'lb' on Tue, 04 Jul 2006 03:10:31 GMT, sez: >return type of that class....instead of
>using ref keyword
good point Harish. oh, unless there's just one variable being returned.
'lb' on Tue, 04 Jul 2006 03:11:08 GMT, sez: meant to say:
>return type of that class....instead of
>using ref keyword
good point Harish. oh, as long as there's just one variable being returned.
|