Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ByRef Me for Structure #611

Open
rskar-git opened this issue Jan 15, 2022 · 3 comments
Open

ByRef Me for Structure #611

rskar-git opened this issue Jan 15, 2022 · 3 comments

Comments

@rskar-git
Copy link

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
    }
}
@VBAndCs
Copy link

VBAndCs commented Jan 15, 2022

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.

@DualBrain
Copy link

DualBrain commented Jan 18, 2022

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.

@DualBrain
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants