Google Mail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
Lambda captures in N2960
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 38 - Collapse all  -  Translate all to Translated (View all originals)   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Follow-up To:
Add Cc | Add Follow-up to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers that you hear
 
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 3 Nov, 18:08
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Tue, 3 Nov 2009 12:08:26 CST
Local: Tues 3 Nov 2009 18:08
Subject: Lambda captures in N2960
Two things in N2960's lambda specification surprised me.  First, captures by
value of const/volatile objects seem to yield copies with the same cv qualifiers
as the original.  This means that if the original is const, the copy is const,
too.  That has the interesting implication that mutable lambdas can't modify the
copies of const data in the closure type, because mutable lambdas don't yield
operator()s in the closure type that are mutable (*).  So:

    void example1()
    {
      const int x = 5;
      auto f1 = [=]{ ++x; };             // error, f1's copy of x is const
      auto f2 = [=]() mutable { ++x; };  // still an error, x is const, dammit
    }

Second, the behavior of by-reference capture doesn't seem to be done in terms of
reference data members in the closure type.  Rather, it seems to be done in
terms of name lookup inside the closure expression.  In other words,

    void example2()
    {
      int x = 5;
      auto f = [&]{ ++x; };           // f's type isn't specified to have a
    }                                 // data member corresponding to x

Is my understanding correct?  (I'm not objecting to either of the things above,
I'm just trying to make sure I understand what I'm reading.)

Thanks,

Scott

(*) Or, as I'm sure to explain it some day, "There's no such thing as a const
lambda, but operator()s generated from lambdas are const.  There are mutable
lambdas, but the operator()s generated from them aren't mutable, they're just
not const.  Any questions?"

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile   Translate to Translated (View Original)
 More options 5 Nov, 03:39
Newsgroups: comp.std.c++
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Wed, 4 Nov 2009 21:39:51 CST
Local: Thurs 5 Nov 2009 03:39
Subject: Re: Lambda captures in N2960
On 2009-11-03, Scott Meyers <use...@aristeia.com> wrote:

> Second, the behavior of by-reference capture doesn't seem to be done in terms
> of reference data members in the closure type.  Rather, it seems to be done
> in terms of name lookup inside the closure expression.

What about this:

 {  int x = 3, &y = x; ... }

Here, x and y are indistinguishable. They are aliases for the same memory
location. You can't write code in the place of ... which can tell that x is
somehow original and y is a derived reference. Therefore, for all intents and
purposes, y is just another name for the same thing as x; it is a name
reference.

Yet, it's not incorrect to describe y as a reference, either.

``Reference'' does not imply ``data member of a reference kind'', distinct from
``name lookup''. C++ references really can /do/ name lookup in some situations.

> In other words,

>     void example2()
>     {
>       int x = 5;
>       auto f = [&]{ ++x; };           // f's type isn't specified to have a
>     }                                 // data member corresponding to x

By data member, do you mean that f.x is a valid expression, so that f in fact
has a kind of ``backing structure'' type? Such that perhaps we can even fiddle
with closures using expressions like f.x = 42?

How would that work if f is passed to some other scope, where there isn't any
static type information about its ``backing structure'' type?

Do we add a symbol table to each closure, using which you can do name lookups
at run-time?

(Lisp has symbols, and yet doesn't provide this kind of reflection over
closures, for good reasons! Though implementations provide it as debug info; if
you are at a debug breakpoint in the middle of a closure, it's nice to be able
to see the values of variables by name.)

Other than that, visible data members on closures are a non-starter on many
fronts.

The x lambda [&]{ ++x; } can be understood to be an alias reference of the same
kind as the y in the x and y example: it's a reference, but at the same time
indistinguishable from a name lookup.

These C++ closures are a joke anyway; they are not first class. In Lisp speak,
we would say they are ``downward funargs only''. If the function terminates,
the so-called ``closure'' becomes toast. A better word for this object
would be ``fissure''. :)

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Hyman Rosen  
View profile   Translate to Translated (View Original)
 More options 5 Nov, 22:28
Newsgroups: comp.std.c++
From: Hyman Rosen <hyro...@mail.com>
Date: Thu, 5 Nov 2009 16:28:04 CST
Local: Thurs 5 Nov 2009 22:28
Subject: Re: Lambda captures in N2960

Kaz Kylheku wrote:

    These C++ closures are a joke anyway; they are not first class.

That's false. They can be assigned, stored, composed, and called
repeatedly.

    In Lisp speak, we would say they are ``downward funargs only''.

> If the function terminates, the so-called ``closure'' becomes toast.

That's fine, and is exactly what one expects of C++.
C++ isn't trying to be Lisp, and there is no chance
in C++ of redefining the language to allow automatic
variables to outlast the exiting of their scope.

Nevertheless, lambdas will be incredibly useful.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
CornedBee  
View profile   Translate to Translated (View Original)
 More options 5 Nov, 22:27
Newsgroups: comp.std.c++
From: CornedBee <wasti.r...@gmx.net>
Date: Thu, 5 Nov 2009 16:27:36 CST
Local: Thurs 5 Nov 2009 22:27
Subject: Re: Lambda captures in N2960
On Nov 3, 7:08 pm, Scott Meyers <use...@aristeia.com> wrote:

> Second, the behavior of by-reference capture doesn't seem to be done in terms of
> reference data members in the closure type.  Rather, it seems to be done in
> terms of name lookup inside the closure expression.  In other words,

>     void example2()
>     {
>       int x = 5;
>       auto f = [&]{ ++x; };           // f's type isn't specified to have a
>     }                                 // data member corresponding to x

There is an important reason for this: the reference_closure type
basically requires lambdas that capture everything by reference to be
implemented as a pair of a function pointer and a scope pointer*. So
there is no data member corresponding to x above. There's a data
member pointing to the start of the stack frame of the invocation of
example2 where the lambda was created, and the access to x happens
through an offset to this pointer.

* A compiler could perhaps come up with an alternate implementation,
but there's no motivation to do so.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 5 Nov, 23:27
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Thu, 5 Nov 2009 17:27:23 CST
Local: Thurs 5 Nov 2009 23:27
Subject: Re: Lambda captures in N2960

> These C++ closures are a joke anyway; they are not first class. In Lisp speak,

Thank you, that's very helpful. I am sure people appreciate that
feedback.

> we would say they are ``downward funargs only''. If the function terminates,
> the so-called ``closure'' becomes toast. A better word for this object

You can do capture-by-reference for objects stored on the free store.
You can also
capture-by-value smart pointers. There are ways to do closures that do
not become
"toast". Capturing objects by value makes it easy to capture snapshots
of values.
You can have closures that are useful for a lot of things, without
mandating
garbage collection in the language. C++ lambdas are also useful for
certain
cases that we currently have to use preprocessor macros for. They may
not
be identical to lisp closures, but it's perhaps not possible to have
closures in
C++ that would be identical to closures in other languages. Some
compromises
are necessary, but that doesn't IMHO make C++ lambdas worthless, there
are
many things you can do with them that are very useful.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 6 Nov, 17:55
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Fri, 6 Nov 2009 11:55:21 CST
Local: Fri 6 Nov 2009 17:55
Subject: Re: Lambda captures in N2960
On Nov 6, 12:28 am, Hyman Rosen <hyro...@mail.com> wrote:

> Kaz Kylheku wrote:
>     These C++ closures are a joke anyway; they are not first class.
> That's false. They can be assigned, stored, composed, and called
> repeatedly.

Other parts of that are correct, but the assignment is not.
[expr.prim.lambda]/p18
states that
"The closure type associated with a lambda-expression has a deleted
default constructor and a deleted copy
assignment operator."

The copy assignment is deleted so you can't assign lambdas. You can
copy construct them, though.
Unfortunately I don't recall hearing any explanation as to why they
can't be assigned.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 6 Nov, 17:57
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Fri, 6 Nov 2009 11:57:01 CST
Local: Fri 6 Nov 2009 17:57
Subject: Re: Lambda captures in N2960
On Nov 3, 8:08 pm, Scott Meyers <use...@aristeia.com> wrote:

>     void example1()
>     {
>       const int x = 5;
>       auto f1 = [=]{ ++x; };             // error, f1's copy of x is const
>       auto f2 = [=]() mutable { ++x; };  // still an error, x is const, dammit
>     }

That is correct AFAIK. It would be beneficial to see whether that is a
problem,
we corrected the reach of lambda in order to be able to port
functional code
from other languages to c++, so if there are cases (or existing
algorithms)
where modification of copies in a lambda is necessary, we may want to
revisit that design
decision.

> Second, the behavior of by-reference capture doesn't seem to be done in terms of
> reference data members in the closure type.  Rather, it seems to be done in
> terms of name lookup inside the closure expression.  In other words,

I don't think that's the case. [ext.prim.lambda]/p15 says
"It is unspecified whether additional unnamed non-static data members
are declared
in the closure type for entities captured by reference.", and p22 says
"[ Note: If an entity is implicitly or explicitly captured by
reference, invoking the function call operator of
the corresponding lambda-expression after the lifetime of the entity
has ended is likely to result in undefined
behavior. — end note ]"

I believe the text in p15 attempts to allow for implementations that
store a stack
frame instead of storing the references individually. Now that the
reach of lambda
has been fixed, this text may need to be clarified, because it's
possible to capture
eg. function arguments, and those may be references to objects that
don't live on
the stack and thus storing a stack frame would not work. Still, for
cases where a
stack frame is known to work, it's allowed by the standard. At any
rate, using
objects captured by-reference is not done in terms of name lookup,
because you can
eg. return the lambda, and the names won't necessarily be in scope
when
the lambda is invoked. The capturing will obviously use name lookup,
but the
use of the objects in the lambda body will not.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 6 Nov, 20:56
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Fri, 6 Nov 2009 14:56:17 CST
Local: Fri 6 Nov 2009 20:56
Subject: Re: Lambda captures in N2960
On Nov 6, 7:55 pm, Ville Voutilainen <ville.voutilai...@gmail.com>
wrote:

> The copy assignment is deleted so you can't assign lambdas. You can
> copy construct them, though.
> Unfortunately I don't recall hearing any explanation as to why they
> can't be assigned.

Sorry to reply to myself, but Daveed Vandevoorde helpfully pointed out
that if a closure class contains reference members, the assignment
becomes
difficult to do correctly in all cases. That's the reason why lambdas
can be copy-constructed but not copy-assigned.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile   Translate to Translated (View Original)
 More options 9 Nov, 18:27
Newsgroups: comp.std.c++
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Mon, 9 Nov 2009 12:27:04 CST
Local: Mon 9 Nov 2009 18:27
Subject: Re: Lambda captures in N2960
On 2009-11-05, Hyman Rosen <hyro...@mail.com> wrote:

> Kaz Kylheku wrote:

>     These C++ closures are a joke anyway; they are not first class.

> That's false. They can be assigned, stored, composed, and called
> repeatedly.

Lambda functions that can escape from the environments in which they are
created are commonly known as first class functions.

Of course, you are entitled to demand that people accept some other
definition ``first class'' when discussing functions with you.

Speaking of composed, to what extent is that true?

Composition of higher order functions means that combinator function
accepts some functional arguments, and then returns a new function, which
can
make use of those functions that were passed in.  That is to say, the
composed
function is a closure is formed inside the combinator which escapes from it.
It refers to its constituent functions by means of captured lexical
bindings.

> Nevertheless, lambdas will be incredibly useful.

``Incredibly''?

Even in plain C, we can get all the semantic functionality of
downward-funarg-only non-lambdas with a simple structure and a function
callback pointer. The concept is relatively empty, semantically.

You should be careful throwing adjectives around, because you
can embarrass yourself by what you consider incredible.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-...@netlab.cs.rpi.edu<std-c%2B...@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 9 Nov, 20:59
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Mon, 9 Nov 2009 14:59:26 CST
Local: Mon 9 Nov 2009 20:59
Subject: Re: Lambda captures in N2960

Ville Voutilainen wrote:
> On Nov 3, 8:08 pm, Scott Meyers <use...@aristeia.com> wrote:
>>     void example1()
>>     {
>>       const int x = 5;
>>       auto f1 = [=]{ ++x; };             // error, f1's copy of x is const
>>       auto f2 = [=]() mutable { ++x; };  // still an error, x is const, dammit
>>     }

> That is correct AFAIK. It would be beneficial to see whether that is a
> problem

It's a problem in terms of the mental model of the author of the lambda.  This
would be the only place in C++ where making a copy of a const object yields a
const copy without explicitly saying that a const copy is desired.  Because
non-mutable lambdas yield const operator()s in the resulting closure,
capture-by-copy into non-mutable lambdas already has the effect of making const
copies, so if the author of the lambda goes to the trouble to turn off this
constness by declaring the lambda mutable, it seems to me that the
captured-by-copy data members should no longer be const.

What is the motivation for capturing consts as consts when they are captured by
copy?

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Hyman Rosen  
View profile   Translate to Translated (View Original)
 More options 9 Nov, 21:36
Newsgroups: comp.std.c++
From: Hyman Rosen <hyro...@mail.com>
Date: Mon, 9 Nov 2009 15:36:49 CST
Local: Mon 9 Nov 2009 21:36
Subject: Re: Lambda captures in N2960

Kaz Kylheku wrote:

> Lambda functions that can escape from the environments in which
> they are created are commonly known as first class functions.

Wikipedia says <http://en.wikipedia.org/wiki/First_class_function>:
   the language supports constructing new functions during the
   execution of a program, storing them in data structures,
   passing them as arguments to other functions, and returning
   them as the values of other functions.
This definition does not require them to be able to access local
variables visible in the scope in which they're defined, nor to
outlive variables which they can reference.

> Speaking of composed, to what extent is that true?

I'm thinking something like this, although I'm not all that
familiar with the proposed syntax.
   int x = 0;
   auto f = [&]() { ++x; }
   auto iterate_f = [=](int n) { return [=]() { while (n-- > 0) f(); } }
   iterate_f(10)();
I'm not sure if iterate_f can be replaced by a template.

> ``Incredibly''?

Yes, to pass as function objects to templates. It makes
the standard library much easier to use.

> Even in plain C, we can get all the semantic functionality of
> downward-funarg-only non-lambdas with a simple structure and a function
> callback pointer. The concept is relatively empty, semantically.

But not syntactically, which is what matters.

> You should be careful throwing adjectives around, because you
> can embarrass yourself by what you consider incredible.

I'm not embarrassed by this particular use of incredible.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Anthony Williams  
View profile   Translate to Translated (View Original)
 More options 10 Nov, 20:19
Newsgroups: comp.std.c++
From: Anthony Williams <anthony....@gmail.com>
Date: Tue, 10 Nov 2009 14:19:01 CST
Local: Tues 10 Nov 2009 20:19
Subject: Re: Lambda captures in N2960

It's also the only place in the language that automatically clones an object.

If you code a clone yourself then you get similar behaviour:

template<typename T>
T clone(T&& x)
{
   return T(x);

}

int main()
{
   std::string const a("hello");
   clone(a)+=" world"; // error, clone is const
   std::string b("hello");
   clone(b)+=" world"; // OK, clone is non-const
   clone(std::string("hello"))+=" world"; // OK, clone is non-const
   typedef const std::string const_string;
   clone(const_string("hello"))+=" world"; // error, clone is const

}
> Because
> non-mutable lambdas yield const operator()s in the resulting closure,
> capture-by-copy into non-mutable lambdas already has the effect of making const
> copies, so if the author of the lambda goes to the trouble to turn off this
> constness by declaring the lambda mutable, it seems to me that the
> captured-by-copy data members should no longer be const.

Interesting observation.

> What is the motivation for capturing consts as consts when they are captured by
> copy?

In a mutable lambda, the type of the cloned object is the same as the source.

Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 10 Nov, 20:20
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Tue, 10 Nov 2009 14:20:23 CST
Local: Tues 10 Nov 2009 20:20
Subject: Re: Lambda captures in N2960
On Nov 9, 10:59 pm, Scott Meyers <use...@aristeia.com> wrote:

> What is the motivation for capturing consts as consts when they are captured by
> copy?

I think decltype of the captured variable in the lambda body would be
very
different than decltype of it outside the lambda body. If I remember
correctly,
decltype was one of the reasons why the constness is retained when
capturing.
Whether that's a convincing argument is another matter. I need to do
some digging
in order to find out if there were more reasons for this particular
decision.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 10 Nov, 23:00
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Tue, 10 Nov 2009 17:00:47 CST
Local: Tues 10 Nov 2009 23:00
Subject: Re: Lambda captures in N2960
On Nov 10, 10:20 pm, Ville Voutilainen <ville.voutilai...@gmail.com>
wrote:

> On Nov 9, 10:59 pm, Scott Meyers <use...@aristeia.com> wrote:
> > What is the motivation for capturing consts as consts when they are captured by
> > copy?
> I think decltype of the captured variable in the lambda body would be
> very
> different than decltype of it outside the lambda body. If I remember
> correctly,
> decltype was one of the reasons why the constness is retained when
> capturing.
> Whether that's a convincing argument is another matter. I need to do
> some digging
> in order to find out if there were more reasons for this particular
> decision.

Once again, with the generous help of Daveed Vandevoorde, I found some
additional
explanation:

begin quoth Daveed
One argument is that one would like to translate:

      for (int k = 0; k < n; ++k) {
        /body/
      }

into

      parfor(0, n, [...](int k) {
        /body/
      });

with /body/ essentially unchanged.  (At least, that's my understanding
of that aspect of the argument.)
end quoth Daveed

For that kind of cases, it's perhaps easier to grok lambdas if they
work as a normal loop would.
For the loop, any locals are in scope, and if they are const, you
can't modify them. For the lambda,
the same locals may be implicitly captured, and you still can't modify
the captured copies if the
originals were const. Overload resolution and decltypes are also the
same both in the loop case and
in the lambda case.

That sounds like a very good and reasonable explanation to me.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 10 Nov, 23:00
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Tue, 10 Nov 2009 17:00:39 CST
Local: Tues 10 Nov 2009 23:00
Subject: Re: Lambda captures in N2960

Anthony Williams wrote:
> It's also the only place in the language that automatically clones an object.

I'm not sure what you mean here, but I think it's notable that the capture mode
is "copy," not "clone."  The closure contains a _copy_ of what is captured, not
a "clone" (whatever that means).

> If you code a clone yourself then you get similar behaviour:

> template<typename T>
> T clone(T&& x)
> {
>    return T(x);
> }

> int main()
> {
>    std::string const a("hello");
>    clone(a)+=" world"; // error, clone is const

No, the error is that you can't bind an lvalue (a) to an rvalue reference (T&&).

Really, I don't understand what you mean by "clone," and even if I did, I would
not understand why you seem to believe that the semantics of "copy" should be
different for lambdas than for every other part of the language.

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 06:49
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Wed, 11 Nov 2009 00:49:31 CST
Local: Wed 11 Nov 2009 06:49
Subject: Re: Lambda captures in N2960

I'm missing something, because (1) there are no lambdas in the above and (2)
there is no parfor in or proposed for C++0x.  (Or is "[...]" supposed to be a
lambda?  If so, note that the only case we are talking about is when "[...]" is
actually "[=]" _and_ the lambda is mutable;  see below.)

> For the loop, any locals are in scope, and if they are const, you
> can't modify them. For the lambda,
> the same locals may be implicitly captured, and you still can't modify
> the captured copies if the
> originals were const.

Which, thanks to the implicit constness of operator() in the closure, they'd
still be, even if copied in the usual fashion.  So the question is why locals
captured by copy can't be modified in a mutable lambda.

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Krügler  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 06:50
Newsgroups: comp.std.c++
From: Daniel Krügler <daniel.krueg...@googlemail.com>
Date: Wed, 11 Nov 2009 00:50:08 CST
Local: Wed 11 Nov 2009 06:50
Subject: Re: Lambda captures in N2960
On 11 Nov., 00:00, Scott Meyers <use...@aristeia.com> wrote:

Note that clone() uses the perfect forwarding signature where we
can bind anything, because the argument lvalueness will determine
the actually deduced type.

Greetings from Bremen,

Daniel Krügler

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Anthony Williams  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 18:07
Newsgroups: comp.std.c++
From: Anthony Williams <anthony....@gmail.com>
Date: Wed, 11 Nov 2009 12:07:07 CST
Local: Wed 11 Nov 2009 18:07
Subject: Re: Lambda captures in N2960

Scott Meyers <use...@aristeia.com> writes:
> Anthony Williams wrote:
>> It's also the only place in the language that automatically clones an object.

> I'm not sure what you mean here, but I think it's notable that the capture mode
> is "copy," not "clone."  The closure contains a _copy_ of what is captured, not
> a "clone" (whatever that means).

Sorry. It is the only place where the compiler automatically generates a
whole new object of the same type as another, which it copy-constructs
from the original. Note that even the reference-ness is preserved. It is
a bit like

decltype(x) y(x);

as opposed to

auto y=x;

>> If you code a clone yourself then you get similar behaviour:

>> template<typename T>
>> T clone(T&& x)
>> {
>>    return T(x);
>> }

>> int main()
>> {
>>    std::string const a("hello");
>>    clone(a)+=" world"; // error, clone is const

> No, the error is that you can't bind an lvalue (a) to an rvalue reference (T&&).

As Daniel already pointed out, this is the perfect forwarding
scenario, so lvalues bind too. Actually, the example is wrong since it
will just return a reference to the original: I really needed to remove
the reference type from the return type.

The decltype example above is better.

> Really, I don't understand what you mean by "clone," and even if I did, I would
> not understand why you seem to believe that the semantics of "copy" should be
> different for lambdas than for every other part of the language.

The semantics of the copy are the same as everywhere else. It is just
that the type of the copied object is declared to be *identical* to the
type of the original, whereas in most cases you explicitly specify the
type of the new object.

Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 18:06
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Wed, 11 Nov 2009 12:06:46 CST
Local: Wed 11 Nov 2009 18:06
Subject: Re: Lambda captures in N2960

Daniel Krügler wrote:

    Note that clone() uses the perfect forwarding signature where we
    can bind anything, because the argument lvalueness will determine
    the actually deduced type.

Yes, I realized after I submitted my post that once again I'd been
tripped up by the fact that a T&& parameter in a function template
need not generate a function taking a T&& parameter.  Silly me.  But I
still don't understand what cloning has to do with capture-by-copy.

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ville Voutilainen  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 18:07
Newsgroups: comp.std.c++
From: Ville Voutilainen <ville.voutilai...@gmail.com>
Date: Wed, 11 Nov 2009 12:07:37 CST
Local: Wed 11 Nov 2009 18:07
Subject: Re: Lambda captures in N2960
On Nov 11, 8:49 am, Scott Meyers <use...@aristeia.com> wrote:

> I'm missing something, because (1) there are no lambdas in the above

The [...] is supposed to be a lambda.

> and (2) there is no parfor in or proposed for C++0x.

It is expected that users will try and write such algorithms which
take their
body as a lambda. The algorithm can run multiple bodies in parallel.
There
are many other such ideas floating around, and C++0x lambdas intend
to support such ideas.

> (Or is "[...]" supposed to be a
> lambda?  If so, note that the only case we are talking about is when "[...]" is
> actually "[=]" _and_ the lambda is mutable;  see below.)

Well, you could also write [foo, &bar, &baz] and you would have the
same
issue with the copy of foo.

> > can't modify them. For the lambda,
> > the same locals may be implicitly captured, and you still can't modify
> > the captured copies if the
> > originals were const.
> Which, thanks to the implicit constness of operator() in the closure, they'd
> still be, even if copied in the usual fashion.  So the question is why locals
> captured by copy can't be modified in a mutable lambda.

Mutable lambdas retain the constness of the originals. Immutable
lambdas
add constness. If the copies drop constness, straightforward
transformation from
 a loop to a copying lambda will result in different decltypes and
different overload
resolution. That's the reason why the constness is retained. The
assumption is
that changing decltypes and overload resolution would be a bigger
surprise than
the surprise of not being able to modify copies of const values. I am
unconvinced
that that assumption would be incorrect, and I'm personally not
willing to propose
changes to the behaviour of lambdas in this area.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
gpderetta  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 18:08
Newsgroups: comp.std.c++
From: gpderetta <gpdere...@gmail.com>
Date: Wed, 11 Nov 2009 12:08:00 CST
Subject: Re: Lambda captures in N2960
On Nov 9, 7:27 pm, Kaz Kylheku <kkylh...@gmail.com> wrote:

> On 2009-11-05, Hyman Rosen <hyro...@mail.com> wrote:

> > Kaz Kylheku wrote:

> >     These C++ closures are a joke anyway; they are not first class.

> > That's false. They can be assigned, stored, composed, and called
> > repeatedly.

> Lambda functions that can escape from the environments in which they are
> created are commonly known as first class functions.

C++ lambdas are not restricted to downward funargs. The following is a
perfectly valid example of a lambda that captures (a copy of) its
environment and outlives the scope where it is created.

std::function<int()>  hof()   {
     int x = 5;
    return  [=]{ ++x; return x; };

}

...

auto f = hof();
cout << f(); // prints 6
cout << f(); // prints 7

Of course, if you capture by reference, you may get the usual problems
of references outliving the referenced value. Just don't do it.

--
Giovanni P. Deretta

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 23:19
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Wed, 11 Nov 2009 17:19:42 CST
Local: Wed 11 Nov 2009 23:19
Subject: Re: Lambda captures in N2960

Anthony Williams wrote:

> Sorry. It is the only place where the compiler automatically generates a
> whole new object of the same type as another

...

> The semantics of the copy are the same as everywhere else. It is just
> that the type of the copied object is declared to be *identical* to the
> type of the original, whereas in most cases you explicitly specify the
> type of the new object.

It occurs to me that this is fundamentally my point:  the behavior of
creation of a member in a closure is not like auto and not like
template argument deduction.  It's a different thing, but *why* is it
a different thing?  I realize that C++0x is so simple and regular that
there is a need to introduce gratuitous inconsistency from time to
time just to keep programmers on their toes, but consider:

 const int x = 0;

 auto y = x;    // y is not const

 template<typename T>
 void f(T y);   // y is not const, even if x is passed as an argument

      [=]() mutable { ++x; }  // the lambda's x, which is a copy
                         // of the local x, is const

Is this really a place where we need to make things more semantically irregular?

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
SG  
View profile   Translate to Translated (View Original)
 More options 11 Nov, 23:21
Newsgroups: comp.std.c++
From: SG <s.gesem...@gmail.com>
Date: Wed, 11 Nov 2009 17:21:16 CST
Local: Wed 11 Nov 2009 23:21
Subject: Re: Lambda captures in N2960
On 11 Nov., 19:08, gpderetta wrote:

> C++ lambdas are not restricted to downward funargs. The following is a
> perfectly valid example of a lambda that captures (a copy of) its
> environment and outlives the scope where it is created.

> std::function<int()>  hof()   {
>     int x = 5;
>     return  [=]{ ++x; return x; };
> }

That should be
   return  [=]()mutable->int{ ++x; return x; };
or
   return  [=]()mutable{ return ++x; };

Cheers,
SG

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Anthony Williams  
View profile   Translate to Translated (View Original)
 More options 12 Nov, 17:25
Newsgroups: comp.std.c++
From: Anthony Williams <anthony....@gmail.com>
Date: Thu, 12 Nov 2009 11:25:17 CST
Local: Thurs 12 Nov 2009 17:25
Subject: Re: Lambda captures in N2960

It's hard to try and be regular, because it depends on what you're
comparing to. Consider:

void f()
{
     const int x=42;

     ++x; // compile error

      [=]() mutable { ++x; } // also compile error
      [&]() mutable { ++x; } // also compile error

     int y=42;

     ++y; // OK

      [=]() mutable { ++y; } // OK
      [&]() mutable { ++y; } // OK

}

Lambdas attempt to be consistent with each other, and with the body of
the enclosing function, so that you can freely move between
capture-by-copy and capture-by-reference for a lambda, and between some
code being part of the normal function body or part of a lambda.

I think it's unfortunate that you need to declare your lambda mutable
for complete consistency in this regard, but I also agree with the idea
that lambdas should be const by default as it avoids some classes of
errors.

Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Scott Meyers  
View profile   Translate to Translated (View Original)
 More options 12 Nov, 22:24
Newsgroups: comp.std.c++
From: Scott Meyers <use...@aristeia.com>
Date: Thu, 12 Nov 2009 16:24:12 CST
Local: Thurs 12 Nov 2009 22:24
Subject: Re: Lambda captures in N2960

Anthony Williams wrote:
>      ++y; // OK

>       [=]() mutable { ++y; } // OK
>       [&]() mutable { ++y; } // OK

Yee haw, they both compile, but the first modifies a copy of y while the second
modifies y itself.  In order to get correct behavior, the author of the lambda
has to understand the transformation from lambda to closure and the implications
of copy versus reference capture.  My sense is that the "capture by copy, er, we
mean this new thing sometimes called clone (which itself is a new meaning of the
term 'clone')" rules are designed to help people avoid thinking about the
lambda-to-closure transformation.  That is, in my view, seriously misguided.

> Lambdas attempt to be consistent with each other, and with the body of
> the enclosing function, so that you can freely move between
> capture-by-copy and capture-by-reference for a lambda

Which, as shown above, modifies the semantics of the lambda.

> I think it's unfortunate that you need to declare your lambda mutable
> for complete consistency in this regard, but I also agree with the idea
> that lambdas should be const by default as it avoids some classes of
> errors.

Everything avoids some classes of errors, and preventing errors is important.
But behavioral inconsistency itself leads to opportunities for errors.  Based on
the draft standard, my sense is that the committee assigns virtually no value to
consistency.  How else to explain that omitting parameter lists on non-mutable
lambdas is okay, but omitting them on mutable lambdas is not?  That functions
using trailing return types must be preceded with auto, but lambdas must not?
That implicit narrowing conversions are allowed everywhere in the language
except when brace initializer lists are used?  That unique_ptr is specialized
for arrays but shared_ptr is not?  That shared_ptr offers special cast forms
(e.g., dynamic_pointer_cast), but unique_ptr does not?  That the standard
documents container "requirements", but *none* of the containers it adds
(compared to C++98) satisfy the requirements?  The list is close to endless.
It's actually a remarkable feat that so many things are so inconsistent.  The
draft standard doesn't look so much like something developed by committee as
something developed by several independent committees.

Scott

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


    Reply    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 1 - 25 of 38   Newer >
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google