As I sit here dreading the fate of the doomed Yankees, I find myself pondering the question posed by a friend yesterday about ByRef vs. ByVal. With nothing better to do at the moment, I thought Id take a stab at explaining it.
When creating a method, you can define the given parameters in two ways: ByVal (the default) or ByRef. Whats the difference?
To properly understand it, step back and realize that the parameters are just variable assignments. If you define a method Sub MyMethod(x As Integer)
, calling MyMethod(c)
has the same effect on the parameter x as x = c
.
But this is the important concept behind variables (and properties and parameters): all variables hold a reference to a Thing, and assigning one variable to another assigns the reference to that Thing, never a copy.
Let me say that again. Assigning one variable to another never creates a copy of the Thing you are assigning. This is true if you are assigning an object like a Date or Dictionary, an array, or just a simple String.
Think of it this way. If you build a house, there is only one house no matter how many envelopes you write its address on. You can copy that address 100 times, but youll never gain square footage. The variable is the envelope holding that address.
(Yeah, I know thats an imperfect analogy, but its the best Ive got.)
This behavior is apparent with objects when you assign the Thing in var1 to var2, make a change through var2, and the properties in var1 change too. Thats because the Thing doesnt live in var1 or var2, but out in the ether, and those variables simply provide a path to it.
(This is less apparent when it comes to String because it looks to us like assigning one String variable to another makes a copy. It doesnt, but since you cant change a String, only create a new one, it acts like its a copy.)
This brings us full circle to ByRef vs. ByVal. So whats the difference?
When you use ByVal (the default if you dont specify either), the behavior is the same as if you assigned var1 to var2. Any changes made to the Thing through var2 are reflected through var1, but when you assign a new Thing to var2, it no longer has a relationship to var1. They each hold references to two different Things.
But when you use ByRef, you arent sending a reference to the Thing to your method like you would when assigning one variable to another, you are sending a reference to the variable to your method. This means that any changes made to that parameter within the method are made directly to the variable you used when you called the method.
For example:
MyMethod(orig)
// Different ways of defining MyMethod
Sub MyMethod(x As Date)
x = new Date // orig is unaffected
Sub MyMethod(ByRef x As Date)
x = new Date // orig now has a new Date
In short, unless you specify ByRef, all parameters are passed By Value. And no, I dont care what the docs say, thats how it works. The badly-named ByRef is passing a reference to the calling variable that holds the Thing instead of a reference to the Thing itself.
Where might you use this? The most common is to return multiple values, something you otherwise cannot do directly. For example:
Sub ParseFilename(n As String, ByRef returnPref As String, ByRef returnSuff As String)
dim parts() as string = n.Split( . )
returnSuff = n( n.Ubound )
parts.Remove n.Ubound
returnPref = join( parts, . )
End Sub
dim p as string
dim s as string
ParseFilename( My.Very.Educated.doc, p, s )
// p = My.Very.Educated
// s = doc
// (no, I didnt test this code)
Now that thats off my chest, Ill go watch the Yankees make a stunning comeback and not end their season today.