ByRef vs ByVal Clarification

Brad picture Brad · Dec 8, 2010 · Viewed 50.5k times · Source

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.

Answer

JaredPar picture JaredPar · Dec 8, 2010

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