Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ByRef vs ByVal Clarification

I'm just starting on a class to handle client connections to a TCP server. Here is the code I've written thus far:

Imports System.Net.Sockets
Imports System.Net

Public Class Client
    Private _Socket As Socket

    Public Property Socket As Socket
        Get
            Return _Socket
        End Get
        Set(ByVal value As Socket)
            _Socket = value
        End Set
    End Property

    Public Enum State
        RequestHeader ''#Waiting for, or in the process of receiving, the request header
        ResponseHeader ''#Sending the response header
        Stream ''#Setup is complete, sending regular stream
    End Enum

    Public Sub New()

    End Sub

    Public Sub New(ByRef Socket As Socket)
        Me._Socket = Socket

    End Sub
End Class

So, on my overloaded constructor, I am accepting a reference to an instance of a System.Net.Sockets.Socket, yes?

Now, on my Socket property, when setting the value, it is required to be ByVal. It is my understanding that the instance in memory is copied, and this new instance is passed to value, and my code sets _Socket to reference this instance in memory. Yes?

If this is true, then I can't see why I would want to use properties for anything but native types. I'd imagine there can be quite a performance hit if copying class instances with lots of members. Also, for this code in particular, I'd imagine a copied socket instance wouldn't really work, but I haven't tested it yet.

Anyway, if you could either confirm my understanding, or explain the flaws in my foggy logic, I would greatly appreciate it.

like image 830
Brad Avatar asked Dec 08 '10 00:12

Brad


People also ask

What is the difference between ByVal and ByRef?

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.

What is ByVal and ByRef in VBA?

Using ByVal makes copies of the data, and the copy will only be accessible from within the called sub, while the original data can only be accessed and modified from within the calling sub. Conversely, ByRef allows you to access and modify the original data from both the calling and the called sub.

Is ByRef faster than ByVal?

When passing variables to procedures that are either in the same project or that are methods of an in-process ActiveX component, ByRef is much faster than ByVal. This is because the memory reference gives the called procedure almost instantaneous access to the variable's value.

What is ByRef in Visual Basic?

ByRef in VB.NET means that a reference to the original value will be sent to the function (1). It's almost like the original value is being directly used within the function. Operations like = will affect the original value and be immediately visible in the calling function.


3 Answers

I think you're confusing the concept of references vs. value types and ByVal vs. ByRef. Even though their names are a bit misleading, they are orthogonal issues.

ByVal in VB.NET means that a copy of the provided value will be sent to the function. For value types (Integer, Single, etc.) this will provide a shallow copy of the value. With larger types this can be inefficient. For reference types though (String, class instances) a copy of the reference is passed. Because a copy is passed in mutations to the parameter via = it won't be visible to the calling function.

ByRef in VB.NET means that a reference to the original value will be sent to the function (1). It's almost like the original value is being directly used within the function. Operations like = will affect the original value and be immediately visible in the calling function.

Socket is a reference type (read class) and hence passing it with ByVal is cheap. Even though it does perform a copy it's a copy of the reference, not a copy of the instance.

(1) This is not 100% true though because VB.NET actually supports several kinds of ByRef at the callsite. For more details, see the blog entry The many cases of ByRef


like image 184
JaredPar Avatar answered Sep 22 '22 02:09

JaredPar


Remember that ByVal still passes references. The difference is that you get a copy of the reference.

So, on my overloaded constructor, I am accepting a reference to an instance of a System.Net.Sockets.Socket, yes?

Yes, but the same would be true if you asked for it ByVal instead. The difference is that with ByVal you get a copy of the reference — you have new variable. With ByRef, it's the same variable.

It is my understanding that the instance in memory is copied

Nope. Only the reference is copied. Therefore, you're still working with the same instance.

Here's a code example that explains it more clearly:

Public Class Foo    Public Property Bar As String    Public Sub New(ByVal Bar As String)        Me.Bar = Bar    End Sub End Class  Public Sub RefTest(ByRef Baz As Foo)      Baz.Bar = "Foo"      Baz = new Foo("replaced") End Sub  Public Sub ValTest(ByVal Baz As Foo)     Baz.Bar = "Foo"     Baz = new Foo("replaced") End Sub  Dim MyFoo As New Foo("-") RefTest(MyFoo) Console.WriteLine(MyFoo.Bar) ''# outputs replaced  ValTest(MyFoo) Console.WriteLine(MyFoo.Bar) ''# outputs Foo 
like image 35
Joel Coehoorn Avatar answered Sep 26 '22 02:09

Joel Coehoorn


My understanding has always been that the ByVal/ByRef decision really matters most for value types (on the stack). ByVal/ByRef makes very little difference at all for reference types (on the heap) UNLESS that reference type is immutable like System.String. For mutable objects, it doesn't matter if you pass an object ByRef or ByVal, if you modify it in the method the calling function will see the modifications.

Socket is mutable, so you can pass any which way you want, but if you don't want to keep modifications to the object you need to make a deep copy yourself.

Module Module1

    Sub Main()
        Dim i As Integer = 10
        Console.WriteLine("initial value of int {0}:", i)
        ByValInt(i)
        Console.WriteLine("after byval value of int {0}:", i)
        ByRefInt(i)
        Console.WriteLine("after byref value of int {0}:", i)

        Dim s As String = "hello"
        Console.WriteLine("initial value of str {0}:", s)
        ByValString(s)
        Console.WriteLine("after byval value of str {0}:", s)
        ByRefString(s)
        Console.WriteLine("after byref value of str {0}:", s)

        Dim sb As New System.Text.StringBuilder("hi")
        Console.WriteLine("initial value of string builder {0}:", sb)
        ByValStringBuilder(sb)
        Console.WriteLine("after byval value of string builder {0}:", sb)
        ByRefStringBuilder(sb)
        Console.WriteLine("after byref value of string builder {0}:", sb)

        Console.WriteLine("Done...")
        Console.ReadKey(True)
    End Sub

    Sub ByValInt(ByVal value As Integer)
        value += 1
    End Sub

    Sub ByRefInt(ByRef value As Integer)
        value += 1
    End Sub

    Sub ByValString(ByVal value As String)
        value += " world!"
    End Sub

    Sub ByRefString(ByRef value As String)
        value += " world!"
    End Sub

    Sub ByValStringBuilder(ByVal value As System.Text.StringBuilder)
        value.Append(" world!")
    End Sub

    Sub ByRefStringBuilder(ByRef value As System.Text.StringBuilder)
        value.Append(" world!")
    End Sub

End Module
like image 43
mattmc3 Avatar answered Sep 22 '22 02:09

mattmc3