C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Named auto

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Thu, 29 Sep 2022 20:25:06 +0100
On Thu, 29 Sept 2022 at 18:15, Lénárd Szolnoki via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> I think this could be addressed by two distinct proposals.
>
> 1. allow placeholders to appear in any deduced context (std::vector<auto>)
> 2. allow a placeholder to introduce a name (auto<class T>, auto<int i>
> might appear as a deduced nttp)
>
> Then you can have your vector<auto<class T>> to deduce the value type and
> introduce the name T for that.
>

std::vector<auto> is problematic, because elsewhere auto means a value of
unconstrained type (e.g. in template<auto>).

That's why I'd prefer auto<class T> vector<T>; also because it's
syntactically regular (as soon as you hit `auto<` you know what's going on).

Cheers,
> Lénárd
>
> On 29 September 2022 17:57:27 BST, Keenan Horrigan via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>>
>> > 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.
>>
>> Ah I see, yes the 'T{auto}' syntax doesn't do that, and I think that's
>> okay, because if it were to do that it would lose how terse it is.
>>
>> > But you can't use explicit function template syntax to initialize a
>> local variable in block scope.
>>
>> Yes, to be clear I'm not advocating against your suggestions, I think
>> they are decent and that some form of what you're suggesting is useful and
>> should be added to the language. I'm just advocating for some form of terse
>> syntax to name what 'auto' would otherwise name, for the primary purpose of
>> function parameters. I'm not in any way trying to say that such a terse
>> syntax would solve the entire scope of the problem, because it doesn't, but
>> that doesn't mean that it shouldn't be added.
>>
>> > That is, deducing the typename `char_t` into scope but without it being
>> a template parameter per se.
>>
>> Ahh, that makes sense.
>> ------- Original Message -------
>> On Thursday, September 29th, 2022 at 11:32 AM, Edward Catmur <
>> ecatmur_at_[hidden]> wrote:
>>
>>
>>
>> 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.
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2022-09-29 19:25:19