vblang
vblang copied to clipboard
ByRef Me for Structure
Per https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/program-structure/me-my-mybase-and-myclass : "Me behaves like either an object variable or a structure variable referring to the current instance."
However, the Me of a VB Structure will always be a copy of the instance when it's a parameter to a call, and never the instance itself, including where the call is for a ByRef parameter.
This proposal is to allow the expression ByRef Me to indicate when a reference to the instance is desired instead of its copy when targeting a ByRef parameter.
For example, this VB code, utilizing ByRef Me:
Module Program
Structure PDQ
Public P As Integer
Public D As Decimal
Public Q As Long
Sub FooBar()
Program.FooBar(ByRef Me)
End Sub
End Structure
Sub FooBar(ByRef dst As PDQ)
dst.P = 123
End Sub
Sub Main()
Dim o As PDQ = Nothing
o.FooBar()
' Prints 123 if ByRef Me is used; otherwise 0
Console.WriteLine($"{o.P}")
End Sub
End Module
Would then work the same as ref this in this C# code:
class Program
{
struct PDQ
{
public int P;
public decimal D;
public long Q;
public void FooBar()
{
Program.FooBar(ref this);
}
}
static void FooBar(ref PDQ dst)
{
dst.P = 123;
}
static void Main(string[] args)
{
PDQ o = default;
o.FooBar();
Console.WriteLine($"{o.P}"); // Prints 123
}
}
I like this. I previously proposed to allow us to optionally add ByRef to ref arguments for better clarity of code. But, I don't think both proposals will happen as they need language changes which is not valid now.
I would argue that the underlying behavior is broken (or the documentation is, at the very least, misleading)...
Module ByrefTest
Structure PDQ
Public P As Integer
Public D As Decimal
Public Q As Long
Sub FooBar()
ByrefTest.FooBar(Me)
End Sub
End Structure
Sub FooBar(ByRef dst As PDQ)
dst.P = 123
End Sub
Sub Main()
Dim o As PDQ = Nothing
o.FooBar()
' Prints 0... expecting it to be 123.
Console.WriteLine($"{o.P}")
End Sub
End Module
I slightly modified the original code to reflect the point that, according to the documentation found at:
https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/modifiers/byref?f1url=%3FappId%3DDev16IDEF1%26l%3DEN-US%26k%3Dk(vb.ByRef);k(DevLang-VB)%26rd%3Dtrue
It states that the ByRef keyword "specifies that an argument is passed in such a way that the called procedure can change the value of a variable underlying the argument in the calling code."
I don't see the need to have to specify ByRef in both places. If the method specifies that it is ByRef that should be enough. If you wanted to force it to be ByVal (for whatever reason), we already have a mechanism in place to override that behavior. The problem as I see it is that the documentation suggests one thing but the implementation clearly doesn't follow what the docs specify.
To further illustrate why I believe this is a bug...
Module ByrefTest
Structure PDQ
Public P As Integer
Public D As Decimal
Public Q As Long
Sub FooBar()
ByrefTest.FooBar(Me)
End Sub
End Structure
Sub FooBar(ByRef dst As PDQ)
dst.P = 123
End Sub
Sub Main1()
Dim o As PDQ = Nothing
o.FooBar() ' Call FooBar within the structure...
Console.WriteLine($"{o.P}") ' Output: 0
FooBar(o) ' Call FooBar outside of the structure...
Console.WriteLine($"{o.P}") ' Output: 123
End Sub
End Module
If I modify the sample so that FooBar is called slightly differently, I get two different results... event though I'm essentially executing the same code. The only difference is the usage of Me.