1500 characters remaining
Lexical Closure and Query Comprehension

# Lexical Closure and Query Comprehension

Visual Studio 2008

Binyam Kelile—Visual Basic TeamMicrosoft Corporation

March 2008

## Summary

This article enables you to get an overview of Lexical Closure and the basic concept involved with Query Comprehension in Visual Basic 2008. A previous knowledge of LINQ and Lambda is required to get a better understanding of this article. If you need to read more about LINQ and Lambda click here. (23 printed pages)

## Applies to:

Visual Studio 2008   Visual Basic

## Introduction

Linq is an excellent new capability in VS2008, powerful and flexible at the same time. But like any new technology, it can often seem like a 'black box' in that you know something is going on under the hood to make all this cool stuff work, you just do not know what! The purpose of this article is to push aside some of the mystery and give you an insight into how queries are constructed and passed around.

First, let's set up a standard scenario we are going to work with, a simple query which queries an in-memory collection that determines the students in the class who failed in math (a score of less than 50).

Let's define the schema by using the following class.

Example 1

```
Class Student
Public name As String
Public mathScore As Integer
End Class

```

Here is a small subset of data that we will use as our running example:

Example 2

```
Dim Students() As Student = {New Student With {.name = "Roger", .mathScore = 43}, _
New Student With {.name = "Chris", .mathScore = 37}, _
New Student With {.name = "Sarah", .mathScore = 95}}

```

Given the above data, we can query for all students to get the students in the class who failed in math.

Example 3

```
Dim results = From student In Students _
Where student.mathScore < 50 _
Select student

For Each p In results
MsgBox(p.name)
Next

```

The above LINQ code compiles and runs fine, returning us the names of those students who failed in math. But what exactly is the query above?

Well, all queries are composed of at least three basic concepts: an extension method, lambda expression and closure, which is the main focus of this article. In terms of these basic concepts, here is how the compiler compiles the above query.

The compiler translates the above query comprehension into invocation of method call by splitting the query up into its component parts, pulls the expression embedded in each part of the query, and generates a lambda function that gets passed into method calls of the object being queried. The methods can be instance methods of the object being queried or extension methods that are external to the object which implement the actual execution of the query.

In this case, the translation could be as simple as the following:

Example 4

```
Dim results = Students.Where(Function(student) student.mathScore < 50). _
Select(Function(student) student)

```

The above extension method syntax depends on lambda expressions, which represent inline functions that return the result of an expression. The lambda expression is converted to a delegate and passed to Where and Select extension methods that are available on an instance of a particular type or object that implements an interface called IEnumerable(of T).

Now let's discuss the concept of closure (also known as a 'Lexical Closure').

## Lexical Closures

A Lexical Closure, often referred to as a closure, is not an immediately visible feature to an end user and is not intended to be used directly from your code. But rather it is a compiler-generated class, which is nested in the containing class or module of the outermost function, and contains the local variables or parameters that need to be referred to by other methods.

Let's see an example that will make this clear:

Example 5

```
Class ClosureSample
Sub Example()
Dim passMark As Integer = 50
Dim results = From student In Students _
Where student.mathScore < passMark _
Select student
End Sub
Or
Sub Example(ByVal passMark As Integer)
Dim results = From student In Students _
Where student.mathScore < passMark _
Select student
End Sub
End Class

```

This query retrieves the list of students who failed on math that represented by passMark variable (a score of 50) and when the compiler translates the above query statement into invocation of method call, it first pulls the expression "student.mathScore < passMark" out and generates the following lambda function, which gets passed to the Where extension method that expects a delegate. Then, the Where extension method uses this delegate to filter out the result.

Example 5 — Compiler Generated

```
Public Function _Lambda\$__1(ByVal student As Student) As Boolean
Return (student.mathScore < Me.Local_passMark)
End Function

```

But the question here will be how we can pass the above lambda function into another method, when the "passMark" variable referred by the above lambda function that is not a local variable or parameter of the lambda function, we call it free variable.

Here is the compiler behind-the-scenes trick, commonly known as variable lifting, that extends the lifetime of the "passMark" variable beyond the local function scope using closure, which represents the entirety of everything we need to run a query that facilitates passing the lambda function into another method.

Let's see what the compiler basically does when it needs to extend the lifetime of a local variable beyond the local function scope. Generate the following closure class, which has a field "passMark" and a lambda expression that gets passed to Where extension method and creates a new instance of a closure class inside the Sub Example, and then redirects all variable references into the "local_passMark" of the closure class.

Example 5 — Compiler Generated

```
Friend NotInheritable Class ClosureSample

Friend Class _Closure\$__1Public Sub New(ByVal other As _Closure\$__1)
If (Not other Is Nothing) Then
Me.local_passMark = other.local_passMark
End If
End Sub

Public Function _Lambda\$__1(ByVal student As Student) As Boolean
Return (student.mathScore < Me.local_passMark)
End Function

Public local_passMark As Integer
End Class

Private Shared Function _Lambda\$__2(ByVal student As Student) As Student
Return student
End Function

Sub Example()
Dim closureVariable_A_8 As New _Closure\$__1
closureVariable_A_8.local_passMark = 50
Dim results As IEnumerable(Of Student) = Students.Where(Of
closureVariable_A_8._Lambda\$__1)).Select(Of Student,

End Sub
End Class

```

As I mentioned in the closure definition, the generated closure class lives outside of the method nested in the containing class of the outermost function. Therefore, the Where extension methods created by the above query statement can legally access the local variables captured in the closure and passed into.

Therefore, closure encapsulates all of the data needed for the query to run. This is where the closure concept comes from: the enclosure of everything necessary for the query to run.

## Scope

Closure is structured in Visual Basic based on the concept of scope, which decides where the variables can be used in a program. And for every scope where lifted variables declared, the compiler generates a new "closure" class associated with that scope and lifts the variable into the same closure and all references to the variables are redirected to that closure.

Consider the following query that returns list of students and their letter grade based on their score:

Example 6

```
Module Module1
Sub Example(ByVal scoreRange As Integer)
Select Case scoreRange
Case 80 To 90
Dim gradeB As String = "B"
Dim results = From student In Students _
Where student.mathScore >= 80 _
And student.mathScore <= 90 _
Select New With _
{Key .name = student.name, .finalscore = gradeB}

Case 95 To 100
Dim gradeA As String = "A"
Dim results = From student In Students _
Where student.mathScore >= 95 _
And student.mathScore <= 100 _
Select New With _
{Key .name = student.name, .finalscore = gradeA}
End Select
End Sub
Module

```

In Example 6, the compiler will generate two closure classes for each "Case" block. Let's see what the generated code looks like:

Example 6 —  Compiler Generated

```
Friend NotInheritable Class Module1

Private Shared Function _Lambda\$__1(ByVal student As Student) As Boolean
Return ((student.mathScore >= 80) And (student.mathScore <= 90))
End Function

Private Shared Function _Lambda\$__3(ByVal student As Student) As Boolean
Return ((student.mathScore >= &H5F) And (student.mathScore <= 100))
End Function

Public Shared Sub Example(ByVal scoreRange As Integer)
End Sub

Friend Class _Closure\$__1

Public Sub New(ByVal other As _Closure\$__1)
If (Not other Is Nothing) Then
End If
End Sub

Public Function _Lambda\$__2(ByVal student As Student) As VB\$AnonymousType_0(Of String, String)
Return New VB\$AnonymousType_0(Of String, String)(student.name, Me.local_gradeB)
End Function

End Class

Friend Class _Closure\$__2

Public Sub New(ByVal other As _Closure\$__2)
If (Not other Is Nothing) Then
End If
End Sub

Public Function _Lambda\$__4(ByVal student As Student) As VB\$AnonymousType_0(Of String, String)
Return New VB\$AnonymousType_0(Of String, String)(student.name, Me.local_gradeA)
End Function

End Class

End Class

```

As you can see in the compiler generated code, _Closure\$__1 and _Closure\$__2 are created.

Notice that _Lambda\$__1 and _Lambda\$__3 are generated to get passed to Where extension method outside of the closure class, because they don't refer any lifted local. Therefore, there is no need to generate a closure class if the lambda expression doesn't refer any lifted local.

Then a closure instance will be created at the beginning of each "Case" block. Here is what the query with the closure instance looks like:

Example 6 —  Compiler Generated

```
Public Shared Sub Example(ByVal scoreRange As Integer)
Select Case scoreRange
Case 80 to 90
Dim Closure_ClosureVariable_14_C As New _Closure\$__1
Dim results…
Exit Select
Case 95 to 100
Dim Closure_ClosureVariable_1B_C As New _Closure\$__2
Dim results...
Exit Select
End Select
End Sub

```

Let's modify the previous example to take a look at the case of nested block or variable lifted from different levels of enclosing blocks, where the outermost and innermost blocks declare lifted variable.

Example 7

```
Sub Example(ByVal score As Integer)
Select Case score
Case 90 To 100
Dim gradeB As String = "A"
If score >= 95 Then
Dim type As String = " With Honor"
Dim results = From student In Students _
Where student.mathScore = score _
Select New With _
{Key .name = student.name, _
.finalscore = gradeB, .type = type}
End If
End Select
End Sub

```

From the above example "If" block is nested within "Select...Case" block and "Select...Case" block itself is nested inside Example (...) method block and, the variables declared in each block will have local scope. In this case, the compiler generates a nested closures class. Here is how the compile code looks like:

Example 7 —  Compiler Generated

```
Friend Class _Closure\$__1

Public Sub New(ByVal other As _Closure\$__1)
If (Not other Is Nothing) Then
Me.local_score = other.local_score
End If
End Sub

Public local_score As Integer

Friend Class _Closure\$__2
Public Sub New(ByVal other As _Closure\$__2)
If (Not other Is Nothing) Then
End If
End Sub

Friend Class _Closure\$__3
Public Sub New(ByVal other As _Closure\$__3)
If (Not other Is Nothing) Then
Me.local_type = other.local_type
End If
End Sub

Public Function _Lambda\$__1(ByVal student As Student) As Boolean
Return (student.mathScore = Me.closureVariable_10_8.local_score)
End Function

Public Function _Lambda\$__2(ByVal student As Student) As VB\$AnonymousType_0(Of String, String, String)
Return New VB\$AnonymousType_0(Of String, String, String)(student.name, Me.closureVariable_11_C.local_gradeB, Me.local_type)
End Function

Public local_type As String
Public closureVariable_10_8 As _Closure\$__1
Public closureVariable_11_C As _Closure\$__2
End Class
End Class
End Class

```

If you closely look at the above compiler generated code, you can see that the "_Closure\$__3" class; "_Lambda\$__1" and "_Lambda\$__2" functions are trying to gain access to the "_Closure\$__1" and "_Closure\$__2" local variables called "local_score" and "local_gradeB" respectively. Notice that for deep nested blocks nesting closure will continue recursively.

The lifetime of local variables in Visual Basic determines how long the storage for that variable exists in memory that is equal to the lifetime of the function where it is declared. But, in Visual Basic 9.0, closures allow the lifetime of a local variable to be extended beyond the lifetime of the function.

Imagine I want a list of students who got above 70 in math exam. Using query expression I would write like this:

Example 8

```
Delegate Function Func(ByVal score As Integer) As IEnumerable(Of String)

Function Example(ByVal score As Integer) As IEnumerable(Of String)
Dim results = From student In Students _
Where student.mathScore > score Select student.name

Return results
End Function

Dim temp As Func = New Func(AddressOf Example)

```

In the preceding code "score" is added to the closure referenced by the query expression inside Example function. Creating a delegate in the next line to this function keeps it alive as long as the delegate is alive and hence extends the lifetime of "score" beyond the normal lifetime of Example function.

## Static Locals

A static local is a special type of local variable in Visual Basic, which allows a value to be retained from one call of a function to other. This can be thought of as a global variable as its value remains in memory for the lifetime of the program. The CLR does not support this, but a compiler does this with just a simple compiler trick by creating a shared class-level variable to maintain the value of the static local variable. As a result the variable does not need to be lifted into the closure. Consider the following example:

Example 9

```
Class StaticSample
Sub Example()
Static score As Integer = 97
Dim results = From student In Students _
Where student.mathScore >= score _
Select  student.name
End Sub
End Class

```

In the preceding example compiler doesn't generate closure, but it does generate a lambda, that gets passed into the Select and Where extension methods. The generated lambda will be inside the outermost function class and the compiler generated code looks like the following:

Example 9 —  Compiler Generated

```
Public Class StaticSample

Private Function _Lambda\$__1(ByVal student As Student) As Boolean
Return (student.mathScore >= Me.score)
End Function

Private Shared Function _Lambda\$__2(ByVal student As Student) As String
Return student.name
End Function

Public Sub Example()

Dim results As IEnumerable(Of String) = Students.Where(Of Student)(New Func(Of Student, Boolean)(AddressOf Me._Lambda\$__1)).Select(Of Student, String)(New Func(Of Student, String)(AddressOf sample._Lambda\$__2))

End Sub

Private score As Integer

End Class

```

As you can see, the compiler created a shared class level variable to maintain the value of "score". Therefore, the compiler didn't generate a closure class instead it did generate "_Lambda__1" and "_Lambda\$__2" that gets passed into Where and Select extension methods.

## Generics

VB.NET compiler does the same thing for generic locals as what it does for non-generics. Consider the following example:

Example 10

```
Sub Example(Of T As {Student, New})(ByVal arg As T)
Dim studentObject = arg
Dim results = From student In Students _
Where studentObject.name = student.name _
End Sub

```

Here, the compiler will generate a generic closure class, where a generic local gets lifted. The compiler generated closure class looks like the following:

Example 10 —  Compiler Generated

```
Friend Class _Closure\$__1(Of \$CLS0 As { Student, New })
Public Function _Lambda\$__1(ByVal student As Student) As Boolean
Return (Me.local_studentObject.name = student.name)
End Function

Public local_studentObject As \$CLS0
End Class

```

As you can see in the code, the compiler generated a generic closure class called _Closure\$__1, including the type constraints "Student" and "New".

Note that for every generic lifted variable, the compiler-generated closure class will have generic parameters equal to the captured variables and these type parameters will include any constraints that might be present on the generic local declaration.

In Visual Basic and, of course, in most programming languages, the lifetime of a local variable is not the same as its scope, which is consistent with the way CLR works. You can simply observe this behavior in Visual Basic, that affects two parts of the language, i.e. declared but uninitialized variables and GoTo, with the following example:

Example 11

```
Sub Example()
For i = 0 To 2
Dim score As Integer
Console.WriteLine(score)
score += 2
Next
End Sub

```

The above code will print out: 0, 2, and 4.

You may think that the above statement would print out all 0's. Assuming that the lifetime of a local variable is the same as the scope of the local variable and you may expect that when the code reaches the end of the "For ... Next" block, both the scope and the lifetime of the local variable "score" ends. However, the lifetime of a local variable "score" is not the same as its scope instead it is always that of the entire function, even if the local variable "score" scope is block-level. Since "score" is not explicitly initialized, it would be created and initialized to 0 only once. Therefore, this implies that even if a block is entered more than once, the value of a local variable "score" will be retained from the previous iteration.

But if we include initialization when we declare local variable "score", the above statement would print out all 0's:

Example 12

```
Sub Example()
For i = 0 To 2
Dim score As Integer =0
Console.WriteLine(score)
score += 2
Next
Sub

```

The above code will print out: 0, 0, and 0.

But, what would happen if there is a query statement in between? Consider the following example that returns a number of students who scored 0 and 100.

Example 13

```
Sub Example()
For i = 0 To 1
Dim score As Integer
Dim results = From student In Students _
Where student.mathScore = score _
Select student.mathScore

Console.WriteLine(score)
score += 100
Next
End Sub

```

Since Closures are structured in Visual Basic based on the concept of scope/blocks, that would capture lifted variables called "score" declared in that block, there will no longer be a single instance of those variables per function, and as the result, every iteration will cause a new instance of the closure class to be created and the output would be all 0's.

But to fix this issue here is what the compiler basically does, when it enters a new scope containing a lifted variable, the compiler will check to see if an instance of closure already exists; if so, the compiler will create a new instance of closure and reset the value of the variable from the previous closure.

Note that the compiler only does the above check if it detects a loop or a GoTo in the function where the closure is generated.

Example 14

```
Sub Example()
For i = 0 To 1
Dim closureVariable_F_8 As _Closure\$__1
closureVariable_F_8 = New _Closure\$__1(closureVariable_F_8)
Dim score As Integer
Dim results = From student In Students _
Where student.mathScore = score _
Select student.mathScore
Console.WriteLine(score)
score += 100
Next
End Sub

```

And here is what the closure constructor looks like:

Example 15

```
Public Sub New(ByVal other As _Closure\$__1)
If (Not other Is Nothing) Then
Me.local_score = other.local_score
End If
End Sub

```

So, the preceding examples show you what the compiler basically does to get around the issue.

## Method Call

Method call is one of the possible things to do inside query comprehension. The following is a simple example of calling shared method.

Example 16

```
Class SharedExample
Shared Function GetGrade(ByVal score As Integer) As String
Select Case score
Case 90 To 100
Return "A"
Case 70 To 89
Return "B"
Case Else
Return "C"
End Select
End Function
End Class

Sub Example()
Dim results = From student In Students _
Select New With {Key .name = student.name, _

End Sub

```

Method declared inside a Module or Shared method doesn't need an object instance like a regular method, but rather it is called directly. Therefore, there is no need to create a closure.

But, for instance method, the compiler lifts "Me" into closure as what it does for local variable lifting.

Example 17

```
Class InstanceExample
Function GetGrade(ByVal score As Integer) As String
Select Case score
Case 90 To 100
Return "A"
Case 70 To 89
Return "B"
Case Else
Return "C"
End Select
End Function

Sub Example(ByVal courseName As String)
Dim results = From student In Students _
Select New With {Key .name = student.name, _
.courseName = courseName, _
End Sub
End Class

```

In the above case, the compiler generates closure and lifts "Me" and "courseName" into that closure. And here is what the compiler generated closure code looks like.

Example 17 —  Compiler Generated

```
Public Class InstanceExample
Friend Class _Closure\$__1
Public Sub New(ByVal other As _Closure\$__1)
If (Not other Is Nothing) Then
Me.\$VB\$Me = other.\$VB\$Me
Me.local_courseName = other.local_courseName
End If
End Sub

Public Function _Lambda\$__1(ByVal student As Student) As VB\$AnonymousType_0(Of String, String, String)
Return New VB\$AnonymousType_0(Of String, String, String)(student.name, Me.local_courseName, Me.\$VB\$Me.GetGrade(student.mathScore))

End Function

Public local_courseName As String
Public \$VB\$Me As InstanceExample
End Class
End Class

```

There are cases, of course, where the compiler is smart enough to see through your use and determine in either to generate closure or not, even if you call instance method inside Query Comprehension. For example, consider the following Query Comprehension inside "InstanceExample" class:

Example 18

```
Class InstanceExample
Function GetGrade(ByVal score As Integer) As String
Select Case score
Case 90 To 100
Return "A"
Case 70 To 89
Return "B"
Case Else
Return "C"
End Select
End Function

Sub Example()
Dim results = From student In Students _
Select New With {Key .name = student.name, _
End Sub
End Class

```

In the above case the compiler doesn't generate closures, because the above query expression doesn't refer to any local variables inside Example method that need to be referred to by the compiler-generated lambda expression that can be passed as an argument for the "Select" extension method. Therefore, instead of emitting another wrapper class called closure, the compiler places the generated lambda expression inside an "InstanceExample" class. The following compiled code shows what the compiler basically does for the above query comprehension:

Example 18 —  Compiler Generated

```
Public Class InstanceExample
Private Function _Lambda\$__1(ByVal student As Student) As AnonymousType_0(Of String, String)
Return New AnonymousType_0(Of String, String)(student.name, Me.GetGrade(student.mathScore))
End Function

Public Sub Example()
Dim results As IEnumerable(Of AnonymousType_0(Of String, String)) =
Students.Select(Of Student, AnonymousType_0(Of String,
String))(New Func(Of Student, AnonymousType_0(Of String,
End Sub
End Class

```

Therefore, as you can see, in the previous code example, there are cases where the compiler performs code optimization.

## MyBase/MyClass

MyBase or MyClass are the other possible things to do inside Query Comprehension and will be captured into a closure. Let's see an example that uses MyBase to call to the base class method inside a query expression from a function that overrides this method.

Example 19

```
Module Module1
Public Class Base
Public Overridable Function Example(ByVal score As Integer) As String
Select Case score
Case 90 To 100
Return "A"
Case 70 To 89
Return "B"
Case Else
Return "C"
End Select
End Function
End Class

Class Derived
Inherits Base

Public Overrides Function Example(ByVal score As Integer) As String
Return Nothing
End Function

Public Function Sample(ByVal courseNumber As String) As String
Dim results = From student In Students _
Select New With {Key .name = student.name, _
.course = courseNumber, _
End Function
End Class
End Module

```

Here is what the compiler does behind the scenes to support "MyBase". It generated a method and called mybase inside that method, and then it generated closure and lambda that gets passed to the Select extension method which uses this method and lifts "Me" and "courseNumber" into that closure. The compiler-generated code look like the following:

Example 19 —  Compiler Generated

```
Friend NotInheritable Class Module1

Public Class Base
Public Overridable Function Example(ByVal score As Integer) As String
Dim t_i0 As Integer = score
If (IIf(((t_i0 >= 90) AndAlso (t_i0 <= 100)), 1, 0) <> 0) Then
Return "A"
End If
If (IIf(((t_i0 >= 70) AndAlso (t_i0 <= &H59)), 1, 0) <> 0) Then
Return "B"
End If
Return "C"
End Function
End Class

Public Class Derived
Inherits Base
Public Function Example_MyBase(ByVal p0 As Integer) As String
Return MyBase.Example(p0)
End Function

Public Overrides Function Example(ByVal score As Integer) As String
Return Nothing
End Function

Public Function Sample(ByVal courseNumber As String) As String
Dim Sample As String
Dim closureVariable_23_C As New _Closure\$__1
closureVariable_23_C.\$VB\$Me = Me
closureVariable_23_C.courseNumber = courseNumber
Dim results As IEnumerable(Of VB\$AnonymousType_0(Of String, String,
String)) = Module1.Students.Select(Of Student, VB\$AnonymousType_0(Of String,
String, String))(New  Func(Of Student, VB\$AnonymousType_0(Of String,
Return Sample
End Function

Friend Class _Closure\$__1

Public Function _Lambda\$__1(ByVal student As Student) As
VB\$AnonymousType_0(Of String, String, String)
Return New VB\$AnonymousType_0(Of String, String, String)(student.name,
Me.\$VB\$Local_courseNumber, Me.\$VB\$Me.Example_MyBase(student.mathScore))
End Function

Public courseNumber As String
Public \$VB\$Me As Derived
End Class
End Class

```

Let's see another example for the case of "MyClass" that allows you to call an overridable method of the current instance inside a query expression:

Example 20

```
Module Module1
Public Class Base
Public Overridable Function Example(ByVal score As Integer) As String
Select Case score
Case 90 To 100
Return "A"
Case 70 To 89
Return "B"
Case Else
Return "C"
End Select
End Function

Public Sub Sample(ByVal courseNumber As String)
Dim results = From student In Students _
Select New With {Key .name = student.name, _
.course = courseNumber, _
End Sub
End Class

Class Derived
Inherits Base

Public Overrides Function Example(ByVal score As Integer) As String
Return Nothing
End Function
End Class
End Module

```

In the same way as for "MyBase", the compiler generates a method and calls "MyClass" inside that method, and then generates closure and lambda that gets passed to Select extension method which uses this method and lifts "Me" and "courseNumber" into that closure.  Below is the compiler generated code:

Example 20 —  Compiler Generated

```
Friend NotInheritable Class Module1

Public Class Base
Public Function Example_MyClass(ByVal p0 As Integer) As String
Return Me.Example(p0)
End Function

Public Overridable Function Example(ByVal score As Integer) As String
Dim t_i0 As Integer = score
If (IIf(((t_i0 >= 90) AndAlso (t_i0 <= 100)), 1, 0) <> 0) Then
Return "A"
End If
If (IIf(((t_i0 >= 70) AndAlso (t_i0 <= &H59)), 1, 0) <> 0) Then
Return "B"
End If
Return "C"
End Function

Public Sub Sample(ByVal courseNumber As String)
Dim closureVariable_35_C As New _Closure\$__1
closureVariable_35_C.courseNumber = courseNumber
closureVariable_35_C.\$VB\$Me = Me
Dim results As IEnumerable(Of VB\$AnonymousType_0(Of String, String,
String)) = Module1.Students.Select(Of Student, VB\$AnonymousType_0(Of
String, String, String))(New Func(Of Student, VB\$AnonymousType_0(Of String,
End Sub

Friend Class _Closure\$__1
Public Function _Lambda\$__1(ByVal student As Student) As
VB\$AnonymousType_0(Of String, String, String)
Return New VB\$AnonymousType_0(Of String, String, String)(student.name,
Me.courseNumber, Me.\$VB\$Me.Example_MyClass(student.mathScore))
End Function

Public courseNumber As String
Public \$VB\$Me As Base
End Class
End Class

Public Class Derived
Inherits Base

Public Overrides Function Example(ByVal score As Integer) As String
Return Nothing
End Function
End Class
End Class

```

The preceding examples are to show you what the compiler basically does to use "MyBase" or "MyClass" inside Query Comprehension.

## Restrictions

There are some restrictions you should be aware of regarding lifting variables.

ByRef Parameters

Any reference to a ByRef parameter inside query comprehensions will cause a compile time error. Because, a ByRef parameter allows the value of the argument to be changed in the calling routine. Therefore, it is not legal to arbitrarily extend the lifetime for a ByRef variable.

Example 21

```
Sub Example(ByRef score As Integer)

Dim results = From student In Students _
Where student.mathScore < score Order By student.name _
Ascending Select student.name
End Sub

```

For the above query comprehension, compiler generates the following error:

"error BC36533: 'ByRef' parameter 'arg' cannot be used in a query expression."

"Me" and Structures

Query Comprehension inside a structure will not be allowed to lift "Me", because closure will extend the lifetime of the lifted variable that includes "Me". But, Closure will hold value by reference and also structure is created on the stack. So, it's not possible to lift "Me" of the structure by reference and extend its lifetime in that manner.

Example 22

```
Structure Struct
Private age As Integer
Public Sub Example()
Dim results = From student In Students Select _
New With {.age = age, .name = student.name}
End Sub
End Structure

```

Therefore, the above query statement will cause a compile-time error:

``` "BC36535: Instance members and 'Me' cannot be used within query expressions in structures." ```

```   ```

GoTo

Compiler doesn't allow to GoTo into scope that contains closure.

Example 23

```
Sub Example()
GoTo lable1
While True
Dim score As Integer = 90

lable1:

Dim results = Aggregate student In Students _
Where student.mathScore > score Into Count()

Exit While
End While
End Sub

```

In my earlier example, in the Lifetime shim section, there is an extra work the compiler has to do here. The closure has to be initialized before the local variable "score" is accessed. Therefore, allowing this will make it difficult for the compiler to maintain the previous task. As a result, the above query statement will cause a compile-time error:

``` "error BC36597: 'GoTo lable1' is not valid because 'lable1' is inside a scope that defines a variable that is used in a lambda or query expression." ```

```   ```

Restricted Types

There are some types in the CLR that are restricted types based on where they can be placed and how they can be used, and this placement restriction prevents them from being declared or used as a member field in a class as such. It is not possible to lift this variable. Trying to do so will result in a compile-time error.

Example 24

```
Sub Example()
Dim arg As New ArgIterator
Dim results = From student In Students _
Where arg.GetRemainingCount > 0 Select student.name
End Sub

```

For the above query expression, compiler generates the following error:

``` "error BC36598: Instance of restricted type 'System.ArgIterator' cannot be used in a query expression." ```

## Conclusion

Query Comprehension provides a concise and compositional expression of query with the basic query capabilities that includes different pre-defined query operator keyword such as projection, selection, cross-product, grouping and sorting, which enables you to write SQL like queries directly in your VB code with better IntelliSense experience in the IDE. And query Comprehension is supported by other new features such as Type Inference, Extension Method, Lambda Expression, Anonymous Types and Lexical Closure. Lexical Closure is the main purpose of this article, which is not an immediately visible feature to you and also is not intended to be used directly from your code, but rather it is under the hood compile feature. But knowing and understanding what the compiler do behind the scene will help you to write simple, correct and fast query statement directly from your VB.NET code.

Binyam Kelile is a software development engineer with the Visual Basic test team at Microsoft.