Date: Thu, 27 Feb 2020 12:06:04 -0500
On Thu, Feb 27, 2020 at 5:19 AM Михаил Найденов via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hello, I am aware of the multiple failed attempts at "abbreviated lambda",
> summarized here <https://brevzin.github.io/c++/2020/01/15/abbrev-lambdas/>recently.
> Nevertheless, this feature seems to be too important to abandon and I
> wanted to share some thoughts I have on the subject.
>
> Ultimately, as far as "terseness" (alone) goes, it is the function
> argument that are the biggest culprit
> [](const auto& a, const auto& b) { return a < b; }
>
> As you can see, if we aim to improve verbosity alone, we should look no
> further then the params
>
> With that in mind, I believe we can split the "abbreviated lambda" goal in
> two tasks - one for the params and one for the body, assuming the one,
> regarding the body will be harder because more issues must be solved.
>
Okay, I buy that. At least I don't find it unbelievable. Divide and
conquer: to shorten the whole lambda, first shorten the parameter list, and
also, orthogonally, shorten the function body.
However, in your message you showed only the first part (shortening the
parameter list). Your proposal can't be "We need to do two things; here's
how to do one of them; the other one is harder so I didn't solve it." You
need to present a complete solution. Otherwise, we get halfway down the
road you selected and we discover that it's a dead end.
> The only issue, outlined in the blog regarding params is the double
> parsing - the fact the compiler has to parse until => (if any) to know, if
> it deals with abbr. params .
> [](a) => ; //< arg
> [](a){}; //< no arg, just void(a) signature
>
The other problem is, what is the type of `a`? Should it be considered the
same as `auto a`? Same as `auto&& a`?
There are good reasons to dismiss `auto a` for non-trivially-copyable types
and therefore pick `auto&& a`.
> *Proposal*
>
> Allow lambda arguments to be declared without parentheses.
> A single item introduces an argument with that name.
>
> []a,b { return a < b; }
>
> This way the parser will immediately know with type of param list it deals
> with.
>
> It will be possible to add a type as well
>
> []a, auto b { return a < b; }
>
> The argument list is bound b/w [] and { or mutable or ->
>
> []{ ... }
> []a, b { ... }
> []a, b -> R { ... }
> [=]a, b mutable { ... }
>
Or `constexpr` or `noexcept` or any of the other things that can go in the
post-parameter-list spot, right?
Think about how this syntax will interact with C++20's explicit template
parameters, i.e. how would you express []<class T>(T::type a){} in terse
notation? "You can't use the terse notation for that" is an acceptable
answer, but you should be explicit about it.
Think about how this syntax interacts with contextual keywords and similar
silliness, and whether you care. (You probably don't.) For example,
[]final{} becomes a valid expression, as does []mutable{} — the former is a
lambda of one argument, and the latter is a lambda of zero arguments.
template<class T> void foo();
template<class T> void bar() { foo(T{}); foo([]T{}); } // both are
valid
I see two big reasons to reject this proposal:
(1) It's incomplete. By itself it doesn't solve the problem, and you
haven't shown that going down this road will lead us to the other half of
the solution.
(2) It shuts doors we are already interested in. Specifically, the syntax
[]foo is frequently mentioned as a way of "lifting" an overload set into a
lambda — that is, []foo should mean roughly [](auto&&... as)
noexcept(noexcept(foo(FWD(as)...))) -> decltype(foo(FWD(as)...)) { return
foo(FWD(as)...) }.
std::transform(first, last, []std::toupper); // OK
If you want to take the syntax []foo {}, you'd better be grabbing it for
something that will be *better* than lifting. I don't think you are.
–Arthur
std-proposals_at_[hidden]> wrote:
> Hello, I am aware of the multiple failed attempts at "abbreviated lambda",
> summarized here <https://brevzin.github.io/c++/2020/01/15/abbrev-lambdas/>recently.
> Nevertheless, this feature seems to be too important to abandon and I
> wanted to share some thoughts I have on the subject.
>
> Ultimately, as far as "terseness" (alone) goes, it is the function
> argument that are the biggest culprit
> [](const auto& a, const auto& b) { return a < b; }
>
> As you can see, if we aim to improve verbosity alone, we should look no
> further then the params
>
> With that in mind, I believe we can split the "abbreviated lambda" goal in
> two tasks - one for the params and one for the body, assuming the one,
> regarding the body will be harder because more issues must be solved.
>
Okay, I buy that. At least I don't find it unbelievable. Divide and
conquer: to shorten the whole lambda, first shorten the parameter list, and
also, orthogonally, shorten the function body.
However, in your message you showed only the first part (shortening the
parameter list). Your proposal can't be "We need to do two things; here's
how to do one of them; the other one is harder so I didn't solve it." You
need to present a complete solution. Otherwise, we get halfway down the
road you selected and we discover that it's a dead end.
> The only issue, outlined in the blog regarding params is the double
> parsing - the fact the compiler has to parse until => (if any) to know, if
> it deals with abbr. params .
> [](a) => ; //< arg
> [](a){}; //< no arg, just void(a) signature
>
The other problem is, what is the type of `a`? Should it be considered the
same as `auto a`? Same as `auto&& a`?
There are good reasons to dismiss `auto a` for non-trivially-copyable types
and therefore pick `auto&& a`.
> *Proposal*
>
> Allow lambda arguments to be declared without parentheses.
> A single item introduces an argument with that name.
>
> []a,b { return a < b; }
>
> This way the parser will immediately know with type of param list it deals
> with.
>
> It will be possible to add a type as well
>
> []a, auto b { return a < b; }
>
> The argument list is bound b/w [] and { or mutable or ->
>
> []{ ... }
> []a, b { ... }
> []a, b -> R { ... }
> [=]a, b mutable { ... }
>
Or `constexpr` or `noexcept` or any of the other things that can go in the
post-parameter-list spot, right?
Think about how this syntax will interact with C++20's explicit template
parameters, i.e. how would you express []<class T>(T::type a){} in terse
notation? "You can't use the terse notation for that" is an acceptable
answer, but you should be explicit about it.
Think about how this syntax interacts with contextual keywords and similar
silliness, and whether you care. (You probably don't.) For example,
[]final{} becomes a valid expression, as does []mutable{} — the former is a
lambda of one argument, and the latter is a lambda of zero arguments.
template<class T> void foo();
template<class T> void bar() { foo(T{}); foo([]T{}); } // both are
valid
I see two big reasons to reject this proposal:
(1) It's incomplete. By itself it doesn't solve the problem, and you
haven't shown that going down this road will lead us to the other half of
the solution.
(2) It shuts doors we are already interested in. Specifically, the syntax
[]foo is frequently mentioned as a way of "lifting" an overload set into a
lambda — that is, []foo should mean roughly [](auto&&... as)
noexcept(noexcept(foo(FWD(as)...))) -> decltype(foo(FWD(as)...)) { return
foo(FWD(as)...) }.
std::transform(first, last, []std::toupper); // OK
If you want to take the syntax []foo {}, you'd better be grabbing it for
something that will be *better* than lifting. I don't think you are.
–Arthur
Received on 2020-02-27 11:08:59