Difference between ByVal and ByRef?
Asked Answered
B

9

20

What is the difference? I always use ByVal, but, I don't really have a good idea of when should I and when not...

Blim answered 5/2, 2011 at 18:20 Comment(3)
95%+ of the time you want ByVal, so it's possibly you've been making the right choice all along :) But +1 for the initiative to learn about it.Kochi
Preface: I am not a VB programmer. If it's anything like C or C++, passing ByVal can be expensive if the object is expensive to copy. If you know you're not going to modify it, ByRef could be faster and the function would behave the same.Caballero
I commented the same thing below, but just in case... ByVal does not create a copy of the object (with the exception of value type variables). It creates a new reference to the same object. You are right that ByRef may be faster (doesn't have to create a new reference) but the difference would be insignificant at best.Uterus
H
13

If you pass in a reference, when you modify the value in the method, the variable in the call site will also be modified.

If you pass value, it's the same as if another variable is created at the method, so even if you modify it, the original variable (at the call site) won't have its value changed.

So, indeed, you should usually pass variables as value. Only pass as reference if you have an explicit need to do so.

Heerlen answered 5/2, 2011 at 18:23 Comment(3)
I think it's very important to note that although the original object, when passed byval, cannot be changed, it's child members can beUterus
Indeed, Smudge202, that's important... you can mutate the object members (or, in other words, you can mutate the object). What you can't mutate is the reference, meaning that you can't replace the object with a new object or a null.Heerlen
+1 for clarifying your answer. Also, see the edit on my post below for an interesting pointUterus
P
16

ByRef = You give your friend your term paper (the original) he marks it up and can return it to you.

ByVal = You give him a copy of the term paper and he give you back his changes but you have to put them back in your original yourself.

As simple as I can make it.

Why to use ByRef:
ByRef will pass the POINTER to the object you are passing. If you are in the same memory space, this means passing just the 'word' not the object. The method you are passing it to can make changes in the original object, and does not need to pass them back at all, as they are in the original object. Useful for making large data passes faster. You can also use ByRef to allow use of a SUB rather then a FUNCTION (In VB) since it does not need to pass back the object.

Why not to use ByRef:
Since the method has access to the original, any changes made will be immediate and permanent. If the method fails, the object could be corrupted. Using ByVal will make a copy, pass the whole copy into the method, and then the method will process the info and either return a copy back, report information or do nothing.

Protostele answered 9/3, 2011 at 18:8 Comment(3)
I disagree almost entirely. Using ByVal does NOT make a copy of the object. It creates a new reference pointing to the same object.n You cannot do anything to the original reference, but you can modify the object. Attempting to set the new reference to nothing does not dispose the object, because the previous reference still exists (which keeps the object alive in the eyes of the GC)Uterus
I believe you are correct, but not right :) with By Val, the new object has the scope of the procedure you are calling, and is totally and distinctly editable within the scope of the procedure. Once processing leaves the procedure the object goes out of scope and is recycled (and unavalable). So it does make a full copy of the object you pass in when using by val. By ref passes the pointed to the object, and no additional copy of the object is created.Protostele
@TomVandeStouwe: you're wrong. No new object is created. This is easily testable in any number of different ways (from using a huge object that simply wouldn't fit into memory that many times, to looking at the hashcode).Convent
H
13

If you pass in a reference, when you modify the value in the method, the variable in the call site will also be modified.

If you pass value, it's the same as if another variable is created at the method, so even if you modify it, the original variable (at the call site) won't have its value changed.

So, indeed, you should usually pass variables as value. Only pass as reference if you have an explicit need to do so.

Heerlen answered 5/2, 2011 at 18:23 Comment(3)
I think it's very important to note that although the original object, when passed byval, cannot be changed, it's child members can beUterus
Indeed, Smudge202, that's important... you can mutate the object members (or, in other words, you can mutate the object). What you can't mutate is the reference, meaning that you can't replace the object with a new object or a null.Heerlen
+1 for clarifying your answer. Also, see the edit on my post below for an interesting pointUterus
G
5

ByRef is like a second return value. It passes a reference to the object into the function rather than the object itself. If you change the value of a ByRef parameter in the function, you will see those changes after the function ends. If that wasn't clear enough, read this and this.

Gardas answered 5/2, 2011 at 18:26 Comment(0)
U
5

I know this question has pretty much been answered, but I just wanted to add the following...

The object you pass to a function is subject to ByRef/ByVal, however, if that object contains references to other objects, they can be modified by the called method regardless of ByRef/ByVal. Poor explanation, I know, see code below for a better understanding:

Public Sub Test()
    Dim testCase As List(Of String) = GetNewList()
    ByRefChange1(testCase)
    'testCase = Nothing
    testCase = GetNewList()

    ByValChange1(testCase)
    'testCase is unchanged
    testCase = GetNewList()

    ByRefChange2(testCase)
    'testCase contains the element "ByRef Change 2"
    testCase = GetNewList()

    ByValChange2(testCase)
    'testCase contains the element "ByVal Change 2"

End Sub

Public Function GetNewList() As List(Of String)
    Dim result As List(Of String) = New List(Of String)
    result.Add("Value A")
    result.Add("Value B")
    result.Add("Value C")
    Return result
End Function

Public Sub ByRefChange1(ByRef aList As List(Of String))
    aList = Nothing
End Sub

Public Sub ByValChange1(ByVal aList As List(Of String))
    aList = Nothing
End Sub

Public Sub ByRefChange2(ByRef aList As List(Of String))
    aList.Add("ByRef Change 2")
End Sub

Public Sub ByValChange2(ByVal aList As List(Of String))
    aList.Add("ByVal Change 2")
End Sub

EDIT:

Also, consider if this function was called:

Public Sub ByValChange3(ByVal aList As List(Of String))
    aList.Add("ByVal Change 3")
    aList = New List(Of String)
    aList.Add("ByVal Change 4")
End Sub

What happens in this case is "ByVal Change 3" is added to the callers list, but at the point you specify that "aList = New List" you are then pointing the new reference, to a new object, and become detached from the callers list. Both common sense and might catch you out one day, so something to bear in mind.

Uterus answered 19/4, 2011 at 14:57 Comment(0)
P
0

I hope this answers your question

Sub last_column_process()
Dim last_column As Integer

last_column = 234
MsgBox last_column

trying_byref x:=last_column
MsgBox last_column

trying_byval v:=last_column
MsgBox last_column

End Sub

Sub trying_byref(ByRef x)
x = 345
End Sub

Sub trying_byval(ByRef v)
v = 555
End Sub
Paresthesia answered 30/10, 2015 at 10:40 Comment(0)
N
0

Think there may have been a typo in the last sample: The last sub should be "byval" and not "byref". :)

Also added a msgbox statement in trying_byval so you can understand what is meant.

Sub begin()
Dim last_column As Integer

last_column = 234
MsgBox "Begin:" & last_column

trying_byref x:=last_column
MsgBox "byref:" & last_column

trying_byval v:=last_column
MsgBox "byval:" & last_column
End Sub

Sub trying_byref(ByRef x)
x = 111
End Sub

Sub trying_byval(ByVal v)  '<--not ByRef, that was in sub trying_byref.
v = 222
MsgBox "In Here:" & v
End Sub
Niggling answered 13/12, 2016 at 15:30 Comment(0)
H
0

ByRef, one value will have 2 addresses

So if x=80 (80 is value and x is address, then for example variable y can be 80 as well, and thus 80 can be accessed by x and y)

Hollishollister answered 23/4, 2017 at 7:14 Comment(0)
R
0

Answers by @Tom and @kelloti are helpful. Here's a code example to illustrate further:

Private Function ValMessage(ByVal SomeMessage As String)
    SomeMessage = "Val Val Val" ' <-- this variable modification doesn't persist after the function finishes execution
    ValMessage = "Some Return Value"
End Function

Private Function RefMessage(ByRef SomeMessage As String)
    SomeMessage = "Ref Ref Ref" ' <-- this variable modification persists even after the function finishes execution
    RefMessage = "Some Return Value"
End Function

Private Sub DoStuff()
    Dim OriginalMessage As String
    Dim OtherMessage As String
    Dim AnotherMessage As String

    OriginalMessage = "Original"
    MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Original"

    OtherMessage = ValMessage(OriginalMessage)
    MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Original"

    AnotherMessage = RefMessage(OriginalMessage)
    MsgBox ("ORIGINAL: " & OriginalMessage) '--> "Ref Ref Ref" <--- this is the difference when you pass a paramter by reference
End Sub
Rebato answered 4/4, 2018 at 23:14 Comment(0)
G
0

I will try to explain the difference in simple words.

  • passing argument by value makes it input only parameter. This is the safest way, therefore is used by default in 95% of the cases.

  • passing argument by reference makes it both input and output parameter. The output parameter can be changed inside the function which creates a rarely used side-effect.

Gesso answered 13/6, 2019 at 15:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.