C++ Logo

std-proposals

Advanced search

Re: Terse lambda quick outline of an alternative

From: Михаил Найденов <mihailnajdenov_at_[hidden]>
Date: Fri, 28 Feb 2020 11:17:38 +0200
On Thu, Feb 27, 2020 at 7:06 PM Arthur O'Dwyer via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> 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 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_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2020-02-28 03:20:33