Question about Lamda Expression
vb.net Code:
Sub Test()
Dim y As Integer = 10
Dim Lambda As Func(Of Integer, Integer) = Function(ByVal x) x + y
y = 20
Console.WriteLine(Lambda(5))
End Sub
So the method vb.net use to generate lamda expression is similar to C++ functor.
So far so good.
What value is displayed when you execute this function? If you said 25, you were spot on. Why 25? Well, the compiler captures and rewrites all of the free variables y to the closure's copy, like so:
vb.net Code:
Sub Test()
Dim Closure As New $CLOSURE_Compiler_Generated_Name$
Closure.y = 10
Dim Lambda = AddressOf Closure.Lambda_1
Closure.y = 20
Console.WriteLine(Lambda(5))
End Function
I still do not understand why Microsoft decide to change the second y=20 into closure.y=20?
The first closure.y=10 make sense. In fact, if I were microsoft, a more normal way to generate the code will be to have a variable would be to do
vb.net Code:
Sub Test()
Dim Closure As New $CLOSURE_Compiler_Generated_Name$
y=10
Closure.y = y
Dim Lambda = AddressOf Closure.Lambda_1
'Closure.y = 20 Remove this line.
Console.WriteLine(Lambda(5))
End Function
Why Microsoft do it the microsoft way instead of the way that make more sense? The microsoft way is when y change value then the Lambda variable also change. It becomes a different function. Also what are the rules where microsoft will change y=10 into Closure.y=10?
vb.net Code:
Sub Test()
For I = 1 To 5
StartThread(Function() I + 10)
Next
End Function
Won't work properly because I keeps changing. What I think would happen is that thread may actually be started sometimes latter, say during doevents or latter.
At that time I would have became 5 or 6 and all threads will simply print 15. Wouldn't happen if Microsoft do things the normal my way.
http://msdn.microsoft.com/en-us/magazine/cc163362.aspx
vb.net Code:
Sub Test()
For I = 1 To 5
Dim x = I
StartThread(Function() x + 10)
Next
End Function
How the hell doing Dim x=i change anything?
Microsoft compiler change all occurrence of I=1,2,3,4,5 into Closure.I=1,2,3,4,5
Why microsoft don't do the same for x?
Re: Question about Lamda Expression
With all this said, what exactly are you getting at in regards to a problem in your coding? If Lambda did not exists how would you tackle your problem?
Also wonder what this is
Dim Closure As New $CLOSURE_Compiler_Generated_Name$
Re: Question about Lamda Expression
Yea, you're splitting hairs. VB.NET isn't LISP.
To answer your only question though, Dim x = i creates a new variable with i's value to pass onward to the Lambda. You're correct, there is the very real possibility that a function doesn't happen until the computer decides to start it because it's delegated and being invoked by another thread. It's in delegation until Windows decides to give it the process time to happen. It DOESN'T evaluate the Lambda until that delegate gets invoked though; it's still meta-code. If that Lambda were using the memory position of "I", then it runs the risk of "I" changing before the Lambda gets evaluated. Once the function gets invoked, only THEN is the Lambda evaluated.
The necessity for this is when dealing with multi-threaded processing.
Re: Question about Lamda Expression
What you're stumbling upon is a powerful language feature called closures. To remove it would be to take much computational power out of lambda expressions. In this case, closures cause confusion and get in the way but this is but a simple example.
I think John Skeet makes a good case for closures in this blog article. It concerns C# but VB .NET's support for lambdas is finally equivalent. It doesn't get exciting until the end:
Quote:
A different sort of combination comes when you feed the result of one delegate into another, or curry one delegate to create a new one. All sorts of options become available when you start thinking of the logic as just another type of data.
I'd like to make a reasonable explanation for why closures need to exist, but I'm not quite experienced enough with functional programming to make the strongest case. Here's my attempt.
Here's the first code snippet:
Code:
Sub Test()
For I = 1 To 5
StartThread(Function() I + 10)
Next
End Function
This is a case where closures hurt because it's not what they were designed for. The value of I is enclosed, so all 5 threads return 15. Let's look at the second example and how it changes things:
Code:
Sub Test()
For I = 1 To 5
Dim x = I
StartThread(Function() x + 10)
Next
End Function
In this case, each lambda is enclosing x. Since x is scoped to the loop, each thread gets a *different* x. So in this case you'd get 11, 12, 13, etc. It's not the act of assigning a value to a variable that brings this about, it's the act of assigning unique variables. If you were to make a subtle change to that snippet, you'd be right back to getting 15 from all threads:
Code:
Sub Test()
Dim x = 0
For I = 1 To 5
x = I
StartThread(Function() x + 10)
Next
End Function
In this case, there's only one x variable since it's not created each loop iteration. It behaves as if you used I in the lambda.
That's a case where it's not useful; there's a case where it helps. It's the case where closures help that I'm not good at constructing; so far the examples I've come up with are quite complicated. I think that's the deal though: closures are powerful in complicated cases and it would be wrong to limit the power of lambda expressions to make smaller tasks easier.
Re: Question about Lamda Expression
Yap. I realized why putting dim x=i in the loop works.
I was told a long time ago that in VB6, no matter where you put the dim statement, variables are always allocated at the beginning of the function. Not so in vb.net
That's my first question actually.
The way closure works is vb.net will make a special class and all local variables will be a member of that class. Which I think is quite an inefficient way to do so. I think a member of that closure class should change only when the delegate is created or assigned.
So my second question is the design choice. Why Microsoft decided to change the member closure class every time the local variable change? Why not just once?
Re: Question about Lamda Expression
I don't really understand what you're trying to ask. Variables are defined by scope. A variable defined in a loop will be disposed upon next loop cycle. Sure there's a lot of allocation and deallocation of memory, but that's just the way a managed memory model works. It takes the drudgery out of having to worry about memory allocation and recovery.
Re: Question about Lamda Expression
Not in vb6
Anyway I think I understand what's going on.
Re: Question about Lamda Expression
Right, because VB6 isn't an object oriented language, nor a managed language.
Re: Question about Lamda Expression
Quote:
Originally Posted by
teguh123
The way closure works is vb.net will make a special class and all local variables will be a member of that class. Which I think is quite an inefficient way to do so. I think a member of that closure class should change only when the delegate is created or assigned.
So my second question is the design choice. Why Microsoft decided to change the member closure class every time the local variable change? Why not just once?
Err, because if they did it the way you describe as an alternative, it wouldn't be a closure.
Re: Question about Lamda Expression
Also, you're missing the trick that when the lambda expression changes the value, the local variable also get changed... it's a two way street.
(Well, it's a no-way non-street because they're the same variable, but since we're talking about a mental model of two copies that get kept in sync...)
Re: Question about Lamda Expression
Quote:
Originally Posted by
teguh123
The way closure works is vb.net will make a special class and all local variables will be a member of that class.
Further, since you do actually seem interested in going into details, only local variables that are referenced in the lambda get made into fields of the generated class.
Re: Question about Lamda Expression
If you're really interested in the nitty-gritty details, I highly recommend Jon Skeet's CLR via C#, particularly the 2nd edition. It devotes 2 or 3 full chapters to lambda delegates, espression trees, and their implementations and implications.
All I can really say without summarizing that book is lambdas and closures work the way they do because if they worked any different they would not be able to do some very advanced things. F# is a great functional language but its adoption has been relatively slow because the C# compiler's (and likewise the VB .NET compiler's) implementation of lambdas brings many of the desirable features of functional programming to the table. It's true that lambdas sometimes make simple things harder, but I believe it's right to pick the correct tool for the job. You wouldn't use a drill press to punch holes in paper: you'd use a hole punch. So don't use lambdas for things they make harder.