3

Today I've witnessed some very strange behavior in VB.NET. The code I am talking about is the following:

Option Strict On
Option Explicit On

Module Module1

    Sub Main()
        Dim thisShouldBeSet = False

        DoSomething(Function() thisShouldBeSet = True)

        If Not thisShouldBeSet Then
            Throw New Exception()
        End If

        Console.WriteLine("yaay")
    End Sub

    Sub DoSomething(action As Action)
        action.Invoke()
    End Sub
End Module

I know that the code in itself is flawed because I must use :

DoSomething(Sub() thisShouldBeSet = True)

Instead of:

DoSomething(Function() thisShouldBeSet = True)

But I find it very odd that even with Option Strict and Option Explicit On the compile allows me to compile this code.

What is even stranger is that when running the code the Action actually behaves like a Func(of Boolean).

Can anyone provide me with a valid explanation to why this is allowed in VB.NET? Is this a compiler / runtime bug?

Luc Bos
  • 1,722
  • 1
  • 13
  • 24

2 Answers2

8

Why should it not allow you to compile the code? thisShouldBeSet = True is a valid comparison, returning the value False (because thisShouldBeSet <> True). Remember that = in VB can mean both = (assignment) and == (comparison) in C#, depending on the context.

To elaborate, Sub() thisShouldBeSet = True would be a shorthand for

Sub Anonymous()
    thisShouldBeSet = True           ' Assignment
End Sub

whereas Function() thisShouldBeSet = True is a shorthand for

Function Anonymous() As Boolean
    Return thisShouldBeSet = True    ' Comparison
End Sub

In VB, it is explicitly allowed to use a function with a return value as an Action. From the documentation of the System.Action delegate (highlighting by me):

In C#, the method must return void. In Visual Basic, it must be defined by the Sub…End Sub construct. It can also be a method that returns a value that is ignored.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • A function does not behave like an action because it has a return type. If I type in C# DoSomething(() => thisShouldBeSet == True) then it does not (and should not) compile. An Action cannot have a return value. – Luc Bos Sep 22 '11 at 13:19
  • 2
    @Luc: In VB, an action *can* have a return value, which is ignored. See my edit. – Heinzi Sep 22 '11 at 13:20
  • I do not see how an Sub can have a return value. If I write the following code: Sub Huh() Return True End Sub Then it does not compile. Neither does: DoSomething(Sub() Return thisShouldBeSet = True End Sub) – Luc Bos Sep 22 '11 at 13:24
  • The documentation does not talk about "a Sub with a return value". It talks about "a **method** with a return value", which is declared in VB using the `Function` keyword. – Heinzi Sep 22 '11 at 13:26
  • Okay, I think I see your point now. So the Action will accept any form of method be it with a return value (Function) or not (Sub). So if I have Function Huh() Return True End Function then I can just use Dim a As New Action(AddressOf Huh). – Luc Bos Sep 22 '11 at 13:32
  • 1
    @Luc: Exactly, that should be possible (can't test right now, don't have Visual Studio here). – Heinzi Sep 22 '11 at 13:36
  • +1 nice blog post on this just recently by bill mccarthy http://msmvps.com/blogs/bill/archive/2011/09/24/vb-quark-1.aspx – MarkJ Sep 25 '11 at 13:44
  • 1
    @MarkJ: Thanks for the link; here's one that links directly to the correct blog post (quark 0 instead of 1): http://msmvps.com/blogs/bill/archive/2011/09/23/vb-quark-0.aspx – Heinzi Sep 25 '11 at 16:11
1

What's going on here is that you are creating a closure.

Your lamdba method behaves like a function rather than a sub in both cases because you have captured/closed over the thisShouldBeSet variable from the Main method, and the thisShouldBeSet = True expression for the Sub interprets the = operator as an assignment rather a comparison.

Community
  • 1
  • 1
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794