Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Func vs Function in VB

Tags:

vb.net

lambda

Would anyone be able to tell me what is the difference between a Func and a Function in VB.

For instance see the following:

Dim F As Func(Of String) = Function() As String
                             Return "B"
                           End Function
Dim F2 = Function() As String
           Return "B"
         End Function
  • F appears as a Func(Of String)
  • F2 as a Function() As String.

It looks like they do the same thing but given that the compiler sees them as having different types surely there must be a subtlity.

Best regards

Charles

like image 854
Charles Avatar asked Jul 04 '13 11:07

Charles


2 Answers

Func(Of TResult)() is a specific delegate with the name Func. It is a type declared inside the System namespace as follows:

Public Delegate Function Func(Of TResult)() As TResult

It could have been named differently. For instance:

Public Delegate Function MyParameterLessFunction(Of TResult)() As TResult

So Func is really just the name given to a delegate. Since the type of F2 is not specified explicitly, VB does not know a name for this delegate. Is it Func or MyParameterLessFunction or something else? Instead, VB just displays its signature Function() As String, since F2 does also fit a non-generic delegate declared as

Public Delegate Function AnonymousParameterLessStringFunction() As String

In your comment you use .ToString() on F and F2. This returns the run-time types, i.e., the types of the values assigned to these variables. These types can be different from the static types of these variables, i.e., the type given to the variable name. Let's make a little test

Imports System.Reflection

Module FuncVsFunction
    Dim F As Func(Of String) = Function() As String
                                   Return "B"
                               End Function
    Dim F2 = Function() As String
                 Return "B"
             End Function

    Sub Test()
        Console.WriteLine($"Run-time type of F:  {F.ToString()}")
        Console.WriteLine($"Run-time type of F2: {F2.ToString()}")

        Dim moduleType = GetType(FuncVsFunction)
        Dim fields As IEnumerable(Of FieldInfo) = moduleType _
            .GetMembers(BindingFlags.NonPublic Or BindingFlags.Static) _
            .OfType(Of FieldInfo)

        For Each member In fields
            Console.WriteLine($"Static type of {member.Name}: {member.FieldType.Name}")
        Next
        Console.ReadKey()
    End Sub
End Module

It displays

Run-time type of F:  System.Func`1[System.String]
Run-time type of F2: VB$AnonymousDelegate_0`1[System.String]
Static type of F: System.Func`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Static type of F2: System.Object

Note that F2 is simply typed as Object. This is a surprise. I expected it to be a of a delegate type.


You also see this difference in the debugger. If you set a break point into the Test method and then hover over the Dim keywords of F and F2, a popup displays

'Dim of F (static type)
Delegate Function System.Func(Of Out TResult)() As String

'Dim of F2 (static type)
Class System.Object

If you hover over the variable names

'F (run-time type)
Method = {System.String _Lambda$__0-0()}

'F2 (run-time type)
<generated method>

For F you not only get type information but also the name of the generated method itself. Since F2 is an Object, Visual Studio obviously does not dig as deep as for F.

like image 134
Olivier Jacot-Descombes Avatar answered Oct 12 '22 23:10

Olivier Jacot-Descombes


F appears as a Func(Of String) F2 as a Function() as string.

No, it doesn’t. In both cases the variable type is a delegate that’s equivalent to Func(Of String). Look at the code carefully again – both declarations have two parts; the declaration itself:

Dim F As Func(Of String)
' and
Dim F2

… and the initialisation:

Function() As String
    Return "B"
End Function

' and

Function() As String
    Return "B"
End Function

As you can see, the initialisation is identical. Merely the declaration is different because we omitted the explicit variable type in the second case. Thanks to Option Infer, the compiler can infer it for us.

In fact, the VB language specification has this to say (§8.4.2):

When an expression classified as a lambda method is reclassified as a value in a context where there is no target type (for example, Dim x = Function(a As Integer, b As Integer) a + b), the type of the resulting expression is an anonymous delegate type equivalent to the signature of the lambda method. [emphasis mine]

Finally, what, then, is the difference between Func and Function?

Function is a keyword that introduces a function – either anonymous function (lambda) as in your code, or a “normal” function having a name, as in this code:

Function F() As String
    Return "B"
End Function

Func(Of T…) on the other hand is a generic type for a delegate. A lambda or a delegate can be bound to a variable declared with a fitting Func type. This is happening in your code.

like image 4
Konrad Rudolph Avatar answered Oct 12 '22 23:10

Konrad Rudolph