C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.
At the same time I would like to allow the init-capture of raw pointers as well. Currently using an init-capture with a raw pointer triggers the "Do not use auto to deduce a raw pointer" check [2] and the following code does not compile:auto widget = std::make_unique<Widget>();auto lambda = [widget_raw = widget.get()]() {UseWidget(*widget_raw);}A workaround exists in the following form, but seems less elegant to me:auto widget = std::make_unique<Widget>();auto lambda = [&widget_ref = *widget]() {UseWidget(widget_ref);}As there is no explicit auto that is deduced to a raw pointer, I feel like this case qualifies as a false positive for the check and it should be allowed.
Please let me know what you think,Jan
--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/c828815c-e8d2-468c-ae89-7627e8aab30f%40chromium.org.
C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.
PK
--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAAHOzFA97mKWgUXRYHGtzAUqtY%2B8nsX_Mxnh2jR6Oa0JV4NMGg%40mail.gmail.com.
On Tue, Jan 23, 2018 at 2:54 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:On Tue, Jan 23, 2018 at 6:52 AM, <jdoe...@chromium.org> wrote:C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.There has been controversy on the internal C-style threads about this. No one really supports fully banning this feature, but Chandler Carruth in particular has deep reservations about it:"...we should document that programmers should avoid init captures at all costs. If there is any other way to solve the problem at hand, that would be better. This features is powerful but deeply confusing in both syntax and resulting behavior. People will continually be surprised by the exact behavior and by the compiler error messages they get in the interim. I think we should minimize how much this is used in our codebase. ... I do see the utility of being able to move a unique_ptr into a lambda that becomes move-only itself. However, I find that the init-capture syntax is too high of a price. It is a completely novel syntax with an entirely new set of gotchas and rules that I don't ever want to use, teach, explain, or debug. Will there be places where it is the only remotely reasonable solution? Probably. I would like to wait until that very moment before using the feature."AFAIK, the current stance is "allowed but very strongly discouraged". If we want to allow these in Chromium, we should probably clarify if that's still the internal stance; understand why; and see if we can summarize the recommendations in our public documentation. The public style guide is pretty much silent on this issue.Right, I looked there also and saw nothing. I don't understand what Chandler's concerns are here from the text you quoted. The syntax is assignment, it doesn't seem so out of place to me, anymore than the rest of the lambda syntax.
--Variable shadowing is "a bad thing" generally, so reusing the same variable name seems like a bad practice here just as it would in any other nested scope.Chromium doesn't even use lambdas except for use in a local scope, or in tests. To me this seems harmless but I'd be curious to understand what his concerns are, maybe there are gotchas that were not in the documentation I read about the feature.--PK
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAAHOzFA97mKWgUXRYHGtzAUqtY%2B8nsX_Mxnh2jR6Oa0JV4NMGg%40mail.gmail.com.
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAHtyhaQq1jQwMQa1Z8epv3mdyHsOBTLb%2BfdsGgoAA0pA6cLQzg%40mail.gmail.com.
On Tue, Jan 23, 2018 at 3:07 PM, <dan...@chromium.org> wrote:On Tue, Jan 23, 2018 at 2:54 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:On Tue, Jan 23, 2018 at 6:52 AM, <jdoe...@chromium.org> wrote:C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.There has been controversy on the internal C-style threads about this. No one really supports fully banning this feature, but Chandler Carruth in particular has deep reservations about it:"...we should document that programmers should avoid init captures at all costs. If there is any other way to solve the problem at hand, that would be better. This features is powerful but deeply confusing in both syntax and resulting behavior. People will continually be surprised by the exact behavior and by the compiler error messages they get in the interim. I think we should minimize how much this is used in our codebase. ... I do see the utility of being able to move a unique_ptr into a lambda that becomes move-only itself. However, I find that the init-capture syntax is too high of a price. It is a completely novel syntax with an entirely new set of gotchas and rules that I don't ever want to use, teach, explain, or debug. Will there be places where it is the only remotely reasonable solution? Probably. I would like to wait until that very moment before using the feature."AFAIK, the current stance is "allowed but very strongly discouraged". If we want to allow these in Chromium, we should probably clarify if that's still the internal stance; understand why; and see if we can summarize the recommendations in our public documentation. The public style guide is pretty much silent on this issue.Right, I looked there also and saw nothing. I don't understand what Chandler's concerns are here from the text you quoted. The syntax is assignment, it doesn't seem so out of place to me, anymore than the rest of the lambda syntax.My guess is that declaring a new variable without mentioning a type (or even `auto`) is the cause for concern. I find that pretty wild too.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAHtyhaSUmSuQJwR%3DROVz1uNorPWAJpbw0bqL_LFiN7xgwNHRYg%40mail.gmail.com.
On Tue, Jan 23, 2018 at 2:54 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:On Tue, Jan 23, 2018 at 6:52 AM, <jdoe...@chromium.org> wrote:C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.There has been controversy on the internal C-style threads about this. No one really supports fully banning this feature, but Chandler Carruth in particular has deep reservations about it:"...we should document that programmers should avoid init captures at all costs. If there is any other way to solve the problem at hand, that would be better. This features is powerful but deeply confusing in both syntax and resulting behavior. People will continually be surprised by the exact behavior and by the compiler error messages they get in the interim. I think we should minimize how much this is used in our codebase. ... I do see the utility of being able to move a unique_ptr into a lambda that becomes move-only itself. However, I find that the init-capture syntax is too high of a price. It is a completely novel syntax with an entirely new set of gotchas and rules that I don't ever want to use, teach, explain, or debug. Will there be places where it is the only remotely reasonable solution? Probably. I would like to wait until that very moment before using the feature."AFAIK, the current stance is "allowed but very strongly discouraged". If we want to allow these in Chromium, we should probably clarify if that's still the internal stance; understand why; and see if we can summarize the recommendations in our public documentation. The public style guide is pretty much silent on this issue.Right, I looked there also and saw nothing. I don't understand what Chandler's concerns are here from the text you quoted. The syntax is assignment, it doesn't seem so out of place to me, anymore than the rest of the lambda syntax. Variable shadowing is "a bad thing" generally, so reusing the same variable name seems like a bad practice here just as it would in any other nested scope.Chromium doesn't even use lambdas except for use in a local scope, or in tests. To me this seems harmless but I'd be curious to understand what his concerns are, maybe there are gotchas that were not in the documentation I read about the feature.
The feature can be subtle and its type deduction rules are, from my reading of the internal thread, slightly different than you might naively expect (but this doesn't affect common cases).
Still, given that we discourage use of lambda capture in Chromium so much in general (more than Google does internally) in favour of base::Bind, are there many use cases that would be significantly improved by capture expressions? If the lambda isn't leaving the scope (this is the assumption behind all cases that we allow lambda capture at all, I believe), then in most cases you can fairly easily just capture the unique_ptr by reference with similar effect.
On Tuesday, January 23, 2018 at 10:14:38 PM UTC+1, Jeremy Roman wrote:The feature can be subtle and its type deduction rules are, from my reading of the internal thread, slightly different than you might naively expect (but this doesn't affect common cases).Reading the internal thread it seems like Chandler wrongly assumed the type deduction rules are different between auto and init-captures with regard to braced init lists, but was later corrected by James Dennett. The rules are equivalent: http://eel.is/c++draft/expr.prim.lambda.capture#6
Still, given that we discourage use of lambda capture in Chromium so much in general (more than Google does internally) in favour of base::Bind, are there many use cases that would be significantly improved by capture expressions? If the lambda isn't leaving the scope (this is the assumption behind all cases that we allow lambda capture at all, I believe), then in most cases you can fairly easily just capture the unique_ptr by reference with similar effect.That is true, the usefulness of this feature is rather limited if lambdas don't leave the scope. Even the current notes on the Chromium C++11 / 14 page say so: "Particularly useful to capture move-only types in a lambda when a reference would go out of scope. Less useful without allowing lambdas to outlive the scope."However, I still think this feature can be useful for tests. In tests we already allow capturing lambdas to leave the scope via base::BindLambdaForTesting(). Maybe we can agree to allow init-captures only in tests?One use case where I would like to use this feature can be found in [1]. Here I am triggering a callback to run in the destructor of an object by resetting the only scoped_refptr pointing to it. In the callback I am referring to the not yet destructed object and using methods of the test fixture, thus I also need to capture `this`. A lambda simply capturing the refptr by reference wouldn't work, since by the time the callback runs the refptr is already set to null. Hence I need to capture a different pointer / reference to the actual object. This example might be a bit contrived, and capturing unique_ptrs by move is likely a more common use case.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/6d27084a-1982-4a4c-af0a-5e5ed679814d%40chromium.org.
I would like to revive this thread, as I found another usecase of this feature. I am currently working with Microsoft's UWP [1] APIs, which make use of async operations via the IAsyncOperation interface [2]. This interface has the concept of completion handlers, which will be invoked with the result once the operation is done. Using WRL's Callback [3] class, these handlers can be constructed from any callable, i.e. Lambas, Functors, function pointers and std::function objects [4]. In order to simplify using this API with existing code, I created a wrapper function that takes a IAsyncOperation and a base::OnceCallback. In the function body I then create a WRL::Callback instance, constructed from a move-capturing lambda, that runs the captured OnceCallback once the lambda is invoked. Admittedly, here the lambda does leave the local scope, but it is the most elegant solution. Since it is possible to work around a ban of move captures by either creating an appropriate functor class or using a lambda with base::AdaptCallbackForRepeating, banning this feature does not result in reduced functionality.
Move-capturing lambdas are simply the most concise (and arguably the most elegant) way to achieve the desired functionality. Because of this I would like to formally allow lambda capture expressions. However, I am perfectly fine with adding disclaimers that usage should be (very) rare, and that it should be restricted to move-captures, as value- and reference-captures can be achieved in other ways.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CALB5StZ-Lb7Qniv__JAu6FsJhfDwuzu1kPD%3Dm5SF1ZewhZTx9A%40mail.gmail.com.
PK
- DanaPK
--
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAHtyhaR722G3-FfDsGocqHziL4VC%3DEnWENHFJ7cJut1UnuuvRQ%40mail.gmail.com.
On Fri, May 10, 2019 at 2:03 PM <dan...@chromium.org> wrote:On Tue, Jan 23, 2018 at 4:23 PM Peter Kasting <pkas...@google.com> wrote:On Tue, Jan 23, 2018 at 12:07 PM, <dan...@chromium.org> wrote:On Tue, Jan 23, 2018 at 2:54 PM, 'Peter Kasting' via cxx <c...@chromium.org> wrote:On Tue, Jan 23, 2018 at 6:52 AM, <jdoe...@chromium.org> wrote:C++14 allows init-captures in lambdas [1] of the formauto widget = std::make_unique<Widget>();auto lambda = [widget = std::move(widget)]() {SetWidget(std::move(widget));}While it's usage should be low, it can be convenient for tests when combined with base::BindLambdaForTesting(). As I don't find a good reason to ban this feature I vote for allowing it.There has been controversy on the internal C-style threads about this. No one really supports fully banning this feature, but Chandler Carruth in particular has deep reservations about it:"...we should document that programmers should avoid init captures at all costs. If there is any other way to solve the problem at hand, that would be better. This features is powerful but deeply confusing in both syntax and resulting behavior. People will continually be surprised by the exact behavior and by the compiler error messages they get in the interim. I think we should minimize how much this is used in our codebase. ... I do see the utility of being able to move a unique_ptr into a lambda that becomes move-only itself. However, I find that the init-capture syntax is too high of a price. It is a completely novel syntax with an entirely new set of gotchas and rules that I don't ever want to use, teach, explain, or debug. Will there be places where it is the only remotely reasonable solution? Probably. I would like to wait until that very moment before using the feature."AFAIK, the current stance is "allowed but very strongly discouraged". If we want to allow these in Chromium, we should probably clarify if that's still the internal stance; understand why; and see if we can summarize the recommendations in our public documentation. The public style guide is pretty much silent on this issue.Right, I looked there also and saw nothing. I don't understand what Chandler's concerns are here from the text you quoted. The syntax is assignment, it doesn't seem so out of place to me, anymore than the rest of the lambda syntax. Variable shadowing is "a bad thing" generally, so reusing the same variable name seems like a bad practice here just as it would in any other nested scope.Chromium doesn't even use lambdas except for use in a local scope, or in tests. To me this seems harmless but I'd be curious to understand what his concerns are, maybe there are gotchas that were not in the documentation I read about the feature.I actually agree with you. I think this feature is generally fine and would choose to allow it if it were up to me; and I don't really understand the objections. That's why my hoped-for outcome was that someone figured out precisely what they were and how they fit into Chromium, or what the likely direction of the internal C arbiters would be in the future. Maybe we could confidently say something like "because we only use lambdas in local scopes in Chromium, initializers in captures are fine". Or maybe we couldn't.I think we should.I don't think we need to ban C++ things based on syntax being weird, or we'd have no C++ left. Capturing lambdas are indeed very limited in our code-base, and have very controlled scope outside of tests. So I think these should be allowed.I generally like this feature. My only reservation is if it looks like Google C++ is likely to ban it. Assuming not, I'm on board with allowing with the same caveats as other capturing lambdas.
----- DanaPK
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CAHtyhaR722G3-FfDsGocqHziL4VC%3DEnWENHFJ7cJut1UnuuvRQ%40mail.gmail.com.
You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To post to this group, send email to c...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/CACuR13f09QdNr%2BTqiOzuMUtnGtQVba4Ge7MYnhp4mMf_MdWUPA%40mail.gmail.com.
I reached out to the internal style arbiters and it looks like they will allow capture expressions with the following restrictions:Both of these rules seem very reasonable to me and match how I would have used capture expressions intuitively. Furthermore, rule two seems to address Nico's concern that init-captures allow you to introduce new variables without specifying any type declarations. Technically we are still introducing new variables, but they will have the same name and a similar type (same % cv-ref qualifiers) as the old variable.
- Only use capture expressions if direct capture is not possible. Example:
int foo = 42;auto lambda = [foo=foo] {...};// Bad: Just use [foo] {...} instead.auto bar = std::make_unique<int>(42);auto lambda = [bar=std::move(bar)] {...};// Good: Just using [bar] {...} is not possible.
Note that this allows using capture expressions to capture data members by value, which wasn't possible before. Don't use init captures to introduce new names, i.e. always shadow existing variables (or data members). Example:
class C {
int member_ = 42;
void foo() {
auto lambda = [member=member_] {...};
// Bad: member is a new name. Use [member_=member_] {...}; instead.
}
};I thus propose allowing init-captures with the caveat that their usage should be rare, and that the above rules should be followed. If no-one has strong objections against this, I will send out a CL to this effect shortly.
On Thu, May 16, 2019 at 5:40 AM Jan Wilken Dörrie <jdoe...@chromium.org> wrote:I reached out to the internal style arbiters and it looks like they will allow capture expressions with the following restrictions:Both of these rules seem very reasonable to me and match how I would have used capture expressions intuitively. Furthermore, rule two seems to address Nico's concern that init-captures allow you to introduce new variables without specifying any type declarations. Technically we are still introducing new variables, but they will have the same name and a similar type (same % cv-ref qualifiers) as the old variable.
- Only use capture expressions if direct capture is not possible. Example:
int foo = 42;auto lambda = [foo=foo] {...};// Bad: Just use [foo] {...} instead.auto bar = std::make_unique<int>(42);auto lambda = [bar=std::move(bar)] {...};// Good: Just using [bar] {...} is not possible.
Note that this allows using capture expressions to capture data members by value, which wasn't possible before. Don't use init captures to introduce new names, i.e. always shadow existing variables (or data members). Example:
class C {
int member_ = 42;
void foo() {
auto lambda = [member=member_] {...};
// Bad: member is a new name. Use [member_=member_] {...}; instead.
}
};I thus propose allowing init-captures with the caveat that their usage should be rare, and that the above rules should be followed. If no-one has strong objections against this, I will send out a CL to this effect shortly.sgtm (though I do personally find the second rule a little odd)