2

I am familiar with the difference between ByVal and ByRef.

However, I was confused why I could pass a WinForms control to a sub using ByVal in order to change some of its properties. In a lot of articles "ByVal" is used, and I was confused about that. I was especially confused when the sub actually did change the control's properties. I was wondering how that could be possible when "ByVal" is used. In my understanding, a sub shouldn't be able to manipulate a control if it's passed ByVal.

To test this a little further, I ran the following test code:

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim n As New List(Of String)

        n.Add("test0")

        pAlterList(n)

        Debug.Assert(n(0) = "test0")

    End Sub

    Private Sub pAlterList(ByVal u As List(Of String))

        u(0) = u(0) & "somechange"

    End Sub

End Class

The strange thing is pAlterList (even though it uses ByVal) DOES change the List(Of String).

After the call to the sub, the first item is "test0somechange". In my understanding, this should only happen if the List(Of String) would be passed as "ByRef".

What am I missing here?

tmighty
  • 10,734
  • 21
  • 104
  • 218
  • That is because List(of T) is a reference type. Google ".NET value vs reference type" – Gnbrkm41 Jan 17 '19 at 01:50
  • On the other hand, Value types like Integer or Boolean would behave as expected when passed as value. – Gnbrkm41 Jan 17 '19 at 01:51
  • 1
    It's kind of a subtlety in the wording; when you pass in `n` (a `List`), to `pAlterList`, what you're doing is, passing in the **reference to** `n` by value. There's no builtin way to pass in the `List` itself because `List` is a reference type; the closest analog would be to clone the `List` before passing it in, that's similar to what other languages like C/C++ would do if you passed in the variable instead of a pointer / reference to the variable. See [this answer](https://stackoverflow.com/a/290267/4975230) for more information. – jrh Jan 17 '19 at 01:53

1 Answers1

4

What you're missing is that, for reference types, ByRef only affects whether assigning a new object to the parameter affects the original variable, not whether making changes to the object that the parameter refers to affects the original variable.

Think of it this way. Let's say that you have a team and Joe is the captain of that team. You need to send someone into a room to perform a task. You say "let's get the captain and send them in", so you get Joe and send him into the room. Inside the room, someone asks Joe to take off the blue shirt he is wearing and put on a red one, then they decide that Joe can sit down and they will actually get Andrew, who was already in the room, to perform the task instead. Does that mean that Andrew is now the captain of your team? Of course not. The fact that they used a different person to perform the task inside the room doesn't affect anything outside the room, so Joe is still captain of the team. When you see Joe walk out of the room though, he will be wearing the red shirt they asked him to wear. Changes made to Joe himself inside the room still affect Joe outside the room. That is how ByVal works on reference type parameters in .NET.

To make this real-world scenario work like using ByRef in .NET, you have to accept that, if someone else performed the task inside the room instead of Joe, they would become the captain of your team. That is the sort of thing that pretty much never happens in the real world, which is why ByRef is the oddity in VB.NET, an OO language, and ByVal is the default behaviour.

jmcilhinney
  • 50,448
  • 5
  • 26
  • 46