473,326 Members | 2,126 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,326 software developers and data experts.

lambda usages

I am not understanding what's happening in the code below (from
accelerated c#) -- I know what the outcome but not how .net does it:

using System;
using System.Linq;
public class LambdaTest
{
static void Main()
{
int counter = 0;
WriteStream( () =counter++ );
Console.WriteLine( "Final value of counter: {0}", counter );
}
static void WriteStream( Func<intcounter )
{
for( int i = 0; i < 10; ++i )
{
Console.Write( "{0}, ", counter() );
}
Console.WriteLine();
}
}

From what I understand, we are creating Func generic delegate ,
which is takes no parameters and returns the int. We and to that
delegate we pass local value type counter. Then why would counter
changed upon the retrun from WriteStream? Doesn't WriteSteam operate
on the local counter argument?

need some lambda education....

Thanks
Oct 22 '08 #1
11 1658
"puzzlecracker" <ir*********@gmail.comwrote in message
news:9b**********************************@p49g2000 hsd.googlegroups.com...
I am not understanding what's happening in the code below (from
accelerated c#) -- I know what the outcome but not how .net does it:

using System;
using System.Linq;
public class LambdaTest
{
static void Main()
{
int counter = 0;
WriteStream( () =counter++ );
Console.WriteLine( "Final value of counter: {0}", counter );
}
static void WriteStream( Func<intcounter )
{
for( int i = 0; i < 10; ++i )
{
Console.Write( "{0}, ", counter() );
}
Console.WriteLine();
}
}

From what I understand, we are creating Func generic delegate ,
which is takes no parameters and returns the int. We and to that
delegate we pass local value type counter. Then why would counter
changed upon the retrun from WriteStream? Doesn't WriteSteam operate
on the local counter argument?

need some lambda education....

Thanks
Well, we are not passing counter into the generic delegate, the generic
delegate is using the local counter (local to the outer function) which is
the same value at the same address when updated/modified from the Main
function or the delegate. The "equivalent" method would be:

static int Increment(ref int counter) { counter++; }

By equivalent I mean that counter is being "passed" into the method (by
reference) instead of the method accessing the variable of the parent code
block directly.

I believe this is correct but I'm not 100% so I hope someone else replies if
I'm wrong :)

HTH,
Mythran
Oct 22 '08 #2
Mythran wrote:
"puzzlecracker" <ir*********@gmail.comwrote in message
news:9b**********************************@p49g2000 hsd.googlegroups.com...
>I am not understanding what's happening in the code below (from
accelerated c#) -- I know what the outcome but not how .net does it:

using System;
using System.Linq;
public class LambdaTest
{
static void Main()
{
int counter = 0;
WriteStream( () =counter++ );
Console.WriteLine( "Final value of counter: {0}", counter );
}
static void WriteStream( Func<intcounter )
{
for( int i = 0; i < 10; ++i )
{
Console.Write( "{0}, ", counter() );
}
Console.WriteLine();
}
}

From what I understand, we are creating Func generic delegate ,
which is takes no parameters and returns the int. We and to that
delegate we pass local value type counter. Then why would counter
changed upon the retrun from WriteStream? Doesn't WriteSteam operate
on the local counter argument?

need some lambda education....

Thanks

Well, we are not passing counter into the generic delegate, the
generic delegate is using the local counter (local to the outer
function) which is the same value at the same address when
updated/modified from the Main function or the delegate. The
"equivalent" method would be:
static int Increment(ref int counter) { counter++; }

By equivalent I mean that counter is being "passed" into the method
(by reference) instead of the method accessing the variable of the
parent code block directly.

I believe this is correct but I'm not 100% so I hope someone else
replies if I'm wrong :)
Mostly right, but the difference is that here we have a closure, the
reference to the function's counter variable is part of the delegate. With
a reference argument the caller (i.e. WriteStream) would have to pass the
reference, here the caller isn't involved in any way.
>
HTH,
Mythran

Oct 22 '08 #3
On Oct 22, 2:20*pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Mythran wrote:
"puzzlecracker" <ironsel2...@gmail.comwrote in message
news:9b**********************************@p49g2000 hsd.googlegroups.com....
I am not understanding what's happening in the code below (from
accelerated c#) -- I know what the outcome but not how .net does it:
using System;
using System.Linq;
public class LambdaTest
{
*static void Main()
*{
* * int counter = 0;
* * WriteStream( () =counter++ );
* * Console.WriteLine( "Final value of counter: {0}", counter );
*}
*static void WriteStream( Func<intcounter )
*{
* * *for( int i = 0; i < 10; ++i )
* * *{
* * * * *Console.Write( "{0}, ", counter() );
* * *}
* * *Console.WriteLine();
* }
}
From what *I understand, we are creating Func *generic delegate ,
which is takes no parameters and returns the int. We and to that
delegate we pass local value type counter. Then *why would counter
changed upon the retrun from WriteStream? Doesn't WriteSteam operate
on the local *counter argument?
need some lambda education....
Thanks
Well, we are not passing counter into the generic delegate, the
generic delegate is using the local counter (local to the outer
function) which is the same value at the same address when
updated/modified from the Main function or the delegate. *The
"equivalent" method would be:
static int Increment(ref int counter) { counter++; }
By equivalent I mean that counter is being "passed" into the method
(by reference) instead of the method accessing the variable of the
parent code block directly.
I believe this is correct but I'm not 100% so I hope someone else
replies if I'm wrong :)

Mostly right, but the difference is that here we have a closure, the
reference to the function's counter variable is part of the delegate. *With
a reference argument the caller (i.e. WriteStream) would have to pass the
reference, here the caller isn't involved in any way.
HTH,
Mythran
Does anyone know what how Func is defined and implemented?

Oct 22 '08 #4
On Wed, 22 Oct 2008 09:56:33 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
[...] Then why would counter
changed upon the retrun from WriteStream? Doesn't WriteSteam operate
on the local counter argument?

need some lambda education....
Mythran's reply mostly covers it. The main correction that needs making
is that it's not that Main()'s "counter" local variable is passed by
reference. It's "captured" by the lambda expression. That is, by using
it in the lambda expression (which in this case is basically just a
different way of declaring an anonymous method), the local variable winds
up removed from the stack and being stored on the heap so that it can be
used by the lambda expression even after the Main() method has returned.

This is a significant point. If the variable were simply being passed by
reference, then the lambda expression would be useless after Main() had
returned (ignoring for the moment that Main() is a special method that,
after it returns, terminates the process :) ). By capturing the variable,
the lambda expression remains viable even after the Main() method has
returned.

This has a variety of implications, but one of them is that any time the
lambda expression is executed, it's using the same "counter" variable that
exists in the Main() method. If you modify the variable in the lambda
expression, that's visible in the Main() method as well (and vice a versa).

So, the WriteStream() method invokes the lambda expression ten times, and
each time it's invoked, it increments the local variable in Main(). After
the WriteStream() method returns, that local variable thus has been
incremented ten times.

Pete
Oct 22 '08 #5
On Wed, 22 Oct 2008 11:31:24 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
Does anyone know what how Func is defined and implemented?
Func<Tis just a delegate type. You can declare it yourself if you like:

delegate T Func<T>();

It's not "implemented" at all. But you can create an instance of the type
in a variety of ways, all involving providing a method implementation that
matches the signature of the delegate type. In the case of anonymous
methods, the compiler can infer and cast to the correct type as long as
the anonymous method is compatible (i.e you haven't written it in a way
that is mutually exclusive with the desired type).

Pete
Oct 22 '08 #6
This is a significant point. If the variable were simply being passed by
reference, then the lambda expression would be useless after Main() had
returned (ignoring for the moment that Main() is a special method that,
after it returns, terminates the process :) ). By capturing the variable,
the lambda expression remains viable even after the Main() method has
returned.
Is this really possible? I don't see how you can move life-time of
the local counter variable beyond it's enclosed space, which is main
our case. It's conceptually wrong to prolong a variables lifetime.

Actually, on the second thought: perhaps ones example can be a
returning the of lambada expression from a function which used its
local variable to initialize it...
Someone needs to demonstrate it with an example... any volunteers?
Oct 23 '08 #7
On Oct 22, 3:35 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Wed, 22 Oct 2008 11:31:24 -0700, puzzlecracker <ironsel2...@gmail.com>
wrote:
Does anyone know what how Func is defined and implemented?

Func<Tis just a delegate type. You can declare it yourself if you like:

delegate T Func<T>();

It's not "implemented" at all. But you can create an instance of the type
in a variety of ways, all involving providing a method implementation that
matches the signature of the delegate type. In the case of anonymous
methods, the compiler can infer and cast to the correct type as long as
the anonymous method is compatible (i.e you haven't written it in a way
that is mutually exclusive with the desired type).

Pete
I tend to think of delegates as classes, hence perceived Func as a
functor...am a paltry and recovering C++ developer
Oct 23 '08 #8
On Wed, 22 Oct 2008 19:03:48 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
Does anyone know what how Func is defined and implemented?

Func<Tis just a delegate type. You can declare it yourself if you
like:

delegate T Func<T>();

It's not "implemented" at all. [...]

I tend to think of delegates as classes, hence perceived Func as a
functor...am a paltry and recovering C++ developer
I'm not sure what you mean. A delegate type is a class and a delegate
instance can indeed be thought of as a functor.

There is in fact implementation behind a delegate type, but without a more
specific question it's not clear what you were asking by "defined and
implemented". I thought you were asking about the declared type Func<T>,
as opposed to the Delegate type that provides the implementation. I
suppose saying that Func<Tisn't "implemented at all" is a bit
misleading; obviously there's an implementation somewhere. It's just that
there's nothing special about Func<Tas opposed to other delegate types.

Pete
Oct 23 '08 #9
On Wed, 22 Oct 2008 19:01:01 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
>This is a significant point. If the variable were simply being passed
by
reference, then the lambda expression would be useless after Main() had
returned (ignoring for the moment that Main() is a special method that,
after it returns, terminates the process :) ). By capturing the
variable,
the lambda expression remains viable even after the Main() method has
returned.

Is this really possible?
Yes, of course. I wouldn't have written it otherwise.
I don't see how you can move life-time of
the local counter variable beyond it's enclosed space, which is main
our case. It's conceptually wrong to prolong a variables lifetime.
It's definitely conceptually wrong. Except when it's right. :p
Actually, on the second thought: perhaps ones example can be a
returning the of lambada expression from a function which used its
local variable to initialize it...

Someone needs to demonstrate it with an example... any volunteers?
I thought the original example in this thread demonstrated it reasonably.
But taking your suggestion as a more overt version, here's what the code
would look like:

void MethodA()
{
Func<intfunc = MethodB();

Console.WriteLine(func());
Console.WriteLine(func());
}

Func<intMethodB()
{
int i = 5;

return () =i++;
}

As you suggested, MethodB() returns the delegate. The variable i is
captured by the lambda expression and so the lifetime is moved out of the
local stack frame and into the heap so that the delegate created with the
lambda expression can always access it, even after MethodB() returns.

You'll find that if you call MethodA(), you get 5 and then 6 written to
standard output.

Pete
Oct 23 '08 #10


"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Wed, 22 Oct 2008 19:03:48 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
>Does anyone know what how Func is defined and implemented?

Func<Tis just a delegate type. You can declare it yourself if you
like:

delegate T Func<T>();

It's not "implemented" at all. [...]

I tend to think of delegates as classes, hence perceived Func as a
functor...am a paltry and recovering C++ developer

I'm not sure what you mean. A delegate type is a class and a delegate
instance can indeed be thought of as a functor.
So we might say a delegate type is an interface for functors, or even (dare
I?), a "concept".

Oct 23 '08 #11


"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Wed, 22 Oct 2008 19:01:01 -0700, puzzlecracker <ir*********@gmail.com>
wrote:
>>This is a significant point. If the variable were simply being passed
by
reference, then the lambda expression would be useless after Main() had
returned (ignoring for the moment that Main() is a special method that,
after it returns, terminates the process :) ). By capturing the
variable,
the lambda expression remains viable even after the Main() method has
returned.

Is this really possible?

Yes, of course. I wouldn't have written it otherwise.
>I don't see how you can move life-time of
the local counter variable beyond it's enclosed space, which is main
our case. It's conceptually wrong to prolong a variables lifetime.

It's definitely conceptually wrong. Except when it's right. :p
>Actually, on the second thought: perhaps ones example can be a
returning the of lambada expression from a function which used its
local variable to initialize it...

Someone needs to demonstrate it with an example... any volunteers?

I thought the original example in this thread demonstrated it reasonably.
But taking your suggestion as a more overt version, here's what the code
would look like:

void MethodA()
{
Func<intfunc = MethodB();

Console.WriteLine(func());
Console.WriteLine(func());
}

Func<intMethodB()
{
int i = 5;

return () =i++;
}
Use Reflector on this. You'll find that what looks like a local variable no
longer is. The captured local variables in any scope are moved into a new
anonymous class, which the anonymous delegate (written with lambda syntax
but that doesn't matter) is a member of so it gets the full context.
Something like:
Func<intMethodB()
{
class Closure_Uniquified
{
int i;
int AnonDelegate01() { return i++; }
}
Closure_Uniquified captured = new Closure_Uniquified();
captured.i = 5;
return new Func<int>(captured.AnonDelegate01);
}
>
As you suggested, MethodB() returns the delegate. The variable i is
captured by the lambda expression and so the lifetime is moved out of the
local stack frame and into the heap so that the delegate created with the
lambda expression can always access it, even after MethodB() returns.

You'll find that if you call MethodA(), you get 5 and then 6 written to
standard output.

Pete
Oct 23 '08 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

53
by: Oliver Fromme | last post by:
Hi, I'm trying to write a Python function that parses an expression and builds a function tree from it (recursively). During parsing, lambda functions for the the terms and sub-expressions...
63
by: Stephen Thorne | last post by:
Hi guys, I'm a little worried about the expected disappearance of lambda in python3000. I've had my brain badly broken by functional programming in the past, and I would hate to see things...
26
by: Steven Bethard | last post by:
I thought it might be useful to put the recent lambda threads into perspective a bit. I was wondering what lambda gets used for in "real" code, so I grepped my Python Lib directory. Here are some...
181
by: Tom Anderson | last post by:
Comrades, During our current discussion of the fate of functional constructs in python, someone brought up Guido's bull on the matter: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 ...
4
by: Xah Lee | last post by:
A Lambda Logo Tour (and why LISP languages using λ as logo should not be looked upon kindly) Xah Lee, 2002-02 Dear lispers, The lambda character λ, always struck a awe in me, as with...
23
by: Kaz Kylheku | last post by:
I've been reading the recent cross-posted flamewar, and read Guido's article where he posits that embedding multi-line lambdas in expressions is an unsolvable puzzle. So for the last 15 minutes...
5
by: Octal | last post by:
How does the lambda library actually works. How does it know how to evaluate _1, how does it recognize _1 as a placeholder, how does it then calculate _1+_2, or _1+2 etc. The source files seem a...
21
by: globalrev | last post by:
i have a rough understanding of lambda but so far only have found use for it once(in tkinter when passing lambda as an argument i could circumvent some tricky stuff). what is the point of the...
1
by: Tim H | last post by:
Compiling with g++ 4: This line: if_then_else_return(_1 == 0, 64, _1) When called with a bignum class as an argument yields: /usr/include/boost/lambda/if.hpp: In member function 'RET...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.