C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Named auto

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Thu, 29 Sep 2022 17:32:08 +0100
On Thu, 29 Sept 2022 at 15:56, Keenan Horrigan <friedkeenan_at_[hidden]>
wrote:

> > The issues I have with that syntax are:
> > * looks like it would be difficult/ambiguous to parse/lex (by compilers,
> editors, etc.)
> > * excessively terse - nowhere else do we introduce a type name into
> scope without a keyword preceding it
> > * can't pattern match, deduce non-types or more than one type
> >
> > For that last point, it means that that syntax would not be a complete
> replacement for explicit function template syntax, nor for decltype (+
> worse!) at block scope, so we'd have yet more syntax to teach. I don't
> think much of the claim that C++ is overly complex, but I do feel that
> additions should try to simplify the "modern" subset of the language, i.e.
> those parts that are sufficient to write new code.
>
> The ambiguity of syntax is a concern I had too, would require more
> investigation to determine if it's really an issue, though that effort
> should not be spent before determining if it would be a good syntax in the
> first place.
>
> I can see how one might think it's excessively terse, I think I'd disagree
> though. Yes, type names have never before been introduced without some sort
> of declarative keyword (well, besides god-given types like int), but that
> requirement of a keyword is part of what makes the currently available
> options not terse enough in my opinion.
>
> If I understand correctly what you mean by pattern matching, I think the
> 'T{auto}' syntax can do that, since 'T' would just be naming what 'auto'
> otherwise would take the place of, so you could do 'const T{auto} &var =
> 1;' and the 'T' would name 'int'.
>

By pattern matching, I mean deducing `T` from `std::vector<T>`, or `U` and
`N` from `std::array<U, N>`, or `R` and `A` from `R(*)(A...)`, etc.

You're correct on the other things though, that it can't deduce non-types
> or multiple types, but I'm not sure a terse syntax needs to, since anything
> more than just putting a name to 'auto' would require syntax that is not
> terse enough I feel, and so if you need more complexity you would use the
> explicit function template syntax, which is how the current situation with
> abbreviated function template syntax works.
>

But you can't use explicit function template syntax to initialize a local
variable in block scope.

Thank you for the examples by the way, I think perhaps they could be better
> abstracted in these instances but they do demonstrate a want for block
> scope named deduction (though I'm not sure the last one falls under that
> since it's just sorta normal use of decltype).
>

For the last one I would hope to be able to write:

template <auto<typename char_t, size_t N>
detail_exported::fixed_string<char_t, N> Str> constexpr auto
operator""_cf() {

That is, deducing the typename `char_t` into scope but without it being a
template parameter per se.

I do think the 'T{auto}' syntax could address all the examples you gave, it
> might have issues when used with just plain 'auto' and maybe that 'auto'
> would deduce a 'const' or something which could cause issues with
> 'is_same', but I'm not sure the other syntax suggestions would handle that
> either.
>

That's good reason to use `const` alongside `auto` - and Victor does that,
to his credit. So that should work fine.

Where I expect frustration to arise is when you realize that you actually
wanted to pattern match on the type of the initializer.

------- Original Message -------
> On Thursday, September 29th, 2022 at 6:46 AM, Edward Catmur <
> ecatmur_at_[hidden]> wrote:
>
> On Wed, 28 Sept 2022 at 19:33, Keenan Horrigan <friedkeenan_at_[hidden]>
> wrote:
>
>> > Yes, it's fairly common, and getting more so as previously
>> callback-style code (that could use lambda explicit template syntax) moves
>> to coroutines. It's frustrating when a nicely deduced, constrained and/or
>> pattern matched parameter becomes a coroutine local variable that now can
>> only be matched using the meagre `auto` syntax.
>>
>> Would love to see an example just for my own curiosity, but I'll take
>> your word for it anyhow.
>>
>
> Here's a couple of examples in just one file:
>
>
> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L206-L207
>
> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L317-L318
>
> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L541-L542
>
> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L600-L601
>
> I think your 'using { ... }' syntax would be fine for named deduction for
>> normal variable declarations, though I wouldn't mind e.g. 'auto<class T>'
>> either, though I think the 'using' version is better and more clear. I feel
>> though that that would only solve one aspect of this problem, and not the
>> aspect of deduced function parameter types. Really I just want something
>> that would give me the type that 'auto' would otherwise name in the
>> abbreviated function template syntax, so for me something like
>>
>> void named_auto(T{auto} &&to_be_forwarded);
>>
>> is perfectly acceptable to me. Maybe these separate aspects of this
>> problem should be given separate solutions? That runs the risk of having
>> more than one good way to do named deduction, at least for deduced types,
>> but I feel that may be a fine enough situation.
>>
>
> The issues I have with that syntax are:
> * looks like it would be difficult/ambiguous to parse/lex (by compilers,
> editors, etc.)
> * excessively terse - nowhere else do we introduce a type name into scope
> without a keyword preceding it
> * can't pattern match, deduce non-types or more than one type
>
> For that last point, it means that that syntax would not be a complete
> replacement for explicit function template syntax, nor for decltype (+
> worse!) at block scope, so we'd have yet more syntax to teach. I don't
> think much of the claim that C++ is overly complex, but I do feel that
> additions should try to simplify the "modern" subset of the language, i.e.
> those parts that are sufficient to write new code.
>
> ------- Original Message -------
>> On Wednesday, September 28th, 2022 at 12:48 PM, Edward Catmur <
>> ecatmur_at_[hidden]> wrote:
>>
>>
>>
>> On Wed, 28 Sept 2022 at 17:56, Keenan Horrigan <
>> friedkeenan_at_[hidden]> wrote:
>>
>>> > We already have syntax for function template parameter named
>>> deduction; we don't need another. What we don't have is a syntax for block
>>> scope named deduction.
>>>
>>> Well, we also currently have ways to get the types deduced through your
>>> syntax suggestions, they're just suboptimal (using decltype, remove_cvref
>>> etc.).
>>>
>>
>> Pattern matching the type is very much suboptimal as well; it requires
>> creating helper metaclasses, alias templates etc., or abusing lambdas.
>>
>>> Similarly, I find the current state of named function parameter
>>> deduction suboptimal. We have the normal 'template<...>' syntax, and then
>>> we have the terse syntax with auto-parameters. Right now I steer away from
>>> the terse syntax because when I deduce a type for a function parameter, I
>>> very often want to also name that deduced type, so I might as well use the
>>> 'template<...>' syntax. However, the terse syntax is more concise, and I
>>> would argue more readable were it not for the fact that it necessitates
>>> some use of decltype to name the type, and similarly may require
>>> remove_cvref etc. to be applied. I find this suboptimal, and would very
>>> much enjoy being able to use the terse syntax and some form of "named auto".
>>>
>>
>> There's no reason that `auto<class T> T x` couldn't be accepted in
>> function template parameter position as well; it just feels redundant.
>>
>> Also there's the issue that when supplying function template argument
>> explicitly (as f<A...>(a...)) to a terse function template it's not
>> entirely obvious which template argument corresponds to which argument. But
>> then again, named deduction wouldn't exactly worsen this issue.
>>
>> Truthfully as well, I cannot recall a time where I've wanted to name a
>>> deduced type of a variable that wasn't a function parameter. Is this a
>>> common occurrence for others? It of course would be better to have syntax
>>> that allows for it, but I personally don't find a solution that doesn't
>>> allow named deduction with the abbreviated function template syntax
>>> appealing.
>>>
>>
>> Yes, it's fairly common, and getting more so as previously callback-style
>> code (that could use lambda explicit template syntax) moves to coroutines.
>> It's frustrating when a nicely deduced, constrained and/or pattern matched
>> parameter becomes a coroutine local variable that now can only be matched
>> using the meagre `auto` syntax.
>>
>> ------- Original Message -------
>>> On Wednesday, September 28th, 2022 at 10:39 AM, Edward Catmur <
>>> ecatmur_at_[hidden]> wrote:
>>>
>>> On Wed, 28 Sept 2022 at 16:24, Keenan Horrigan <
>>> friedkeenan_at_[hidden]> wrote:
>>>
>>>> My issue with the 'using' syntax was that it seems redundant when used
>>>> with function parameter type deduction (because why wouldn't you just type
>>>> out the normal 'template<...>'), I don't see how your 'auto<class T> T var'
>>>> syntax addresses that beyond maybe putting the deduced entities closer to
>>>> their source? Not a hugely compelling reason to use it over normal template
>>>> parameters in my opinion.
>>>>
>>>
>>> We already have syntax for function template parameter named deduction;
>>> we don't need another. What we don't have is a syntax for block scope named
>>> deduction.
>>>
>>>> ------- Original Message -------
>>>> On Wednesday, September 28th, 2022 at 10:08 AM, Edward Catmur via
>>>> Std-Proposals <std-proposals_at_[hidden]> wrote:
>>>>
>>>> On Wed, 28 Sept 2022 at 15:14, Jason McKesson via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>> On Wed, Sep 28, 2022 at 10:06 AM S├ębastien Bini via Std-Proposals
>>>>> <std-proposals_at_[hidden]> wrote:
>>>>> >
>>>>> > How about a syntax similar to that of parameters then?
>>>>> >
>>>>> > template <class T> T var = foo();
>>>>> > template <class K, class V> std::pair<K const, V>& kv =
>>>>> *map.begin(); // or [k, v]?
>>>>> > template <std::copyable T, auto I> std::array<T, I> arr = getArr();
>>>>> > template <std::size_t... I> [[maybe_unused]]
>>>>> std::index_sequence<I...> seq = std::index_sequence_for<Args...>();
>>>>> >
>>>>> > Then we don't need to reinvent the syntax for parameters.
>>>>>
>>>>
>>>> That syntax is already in use for variable templates. Maybe named
>>>> deduction is at block scope and variable templates are at namespace scope,
>>>> but that kind of overloading of meaning is pretty horrible - `static` is
>>>> bad enough.
>>>>
>>>> Let's re-examine the problem that people seem to want to solve.
>>>>>
>>>>> My understanding was that the principal problem was that you want to
>>>>> gain access to the actual typename that the placeholder deduction
>>>>> syntax yields, and sticking a `using name = decltype(var_name);` is
>>>>> both wordy and error-prone (I deliberately did that wrong, for
>>>>> example).
>>>>>
>>>>> The main reason people deduce types is because they don't want to have
>>>>> to type out the full name of the type
>>>>
>>>>
>>>> or because the type is unnameable, or because it's dependent, or
>>>> because the code you're calling could change its return type and so typing
>>>> it out is a hostage to fortune.
>>>>
>>>>> (or because it's already
>>>>> mentioned in the initializing expression).
>>>>
>>>>
>>>> If you're using AAA with types on the RHS then you don't need to deduce
>>>> them again, so you wouldn't need named deduction.
>>>>
>>>>> So it seems to me that
>>>>> injecting a bunch more words into such a declaration is...
>>>>> counter-productive.
>>>>>
>>>>> Yes, any of these declarations might be useful. But... are they really
>>>>> *that* useful? So useful that we want to type out (and read) all of
>>>>> that?
>>>>>
>>>>
>>>> We are proposing that a single statement introduce not just potentially
>>>> multiple entity names, but also potentially multiple type aliases (also,
>>>> maybe, packs, templates, concepts). This is a novel challenge for compilers
>>>> and other tools, and it needs *some* introducing syntax to shunt the parser
>>>> down the new code paths; lexing is difficult enough as it is.
>>>>
>>>> If `using` is too much typing, how about the introducer being `auto <`?
>>>> It seems that the lexer should be able to detect that pretty much
>>>> immediately.
>>>>
>>>> auto<class T> T var = foo();
>>>> // etc.
>>>>
>>>>
>>>>
>>>
>>
>

Received on 2022-09-29 16:32:21