On Thu, Feb 27, 2020 at 7:06 PM Arthur O'Dwyer via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Thu, Feb 27, 2020 at 5:19 AM Михаил Найденов via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hello, I am aware of the multiple failed attempts at "abbreviated lambda", summarized here 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 idea is, even if we can't get the forwarding body ever, not having to specify the types is huge win on its own as it is only C++ that requires them in lambda expressions (for no good reason)

 
 
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.

I think one should be able to mix both

[]<class T>T::type a, b {}

We will have again considerable gains here as well, because the explicit tml arg syntax is already big enough.


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.

This is a good point. BTW what happen with "Down with ()!" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1102r0.html ?

In any case, it seems we will need a way to terminate the list, independent of the keyword at the end. Otherwise we are not future proof

class a{};
[]a b { ... } 
 
`b`, becomes a contextual keyword and boom.


    template<class T> void foo();
    template<class T> void bar() { foo(T{}); foo([]T{}); }  // both are 


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.

The lifting (using this syntax) was already presented and rejected no? 

In any case, lifting will be much less of an issue with terse lambdas for the incidental cases, and with the new inline global objects for the common cases
Ultimately, you dont want to generate a new wrapper locally every time

 std::transform(first, last, std::toupper_obj);

 std::toupper_obj being a global wrapper, used by anyone


–Arthur
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals