On Fri, 18 Sep 2020 at 09:36, Richard Hodges via Std-Discussion
<std-discussion@lists.isocpp.org> wrote:
> auto x = tuple [ foo, &bar]; // bar is a tie
> auto x = tuple & [ foo, bar ]; // equivalent to std::tie
>
> In the above trivial example, the presence of the name std::make_tuple adds almost no information. It also creates a type with a long and unwieldy name (that actually causes some compilers to run out of string space!) and an eye-wateringly complex implementation. The presence of std:: adds absolutely none as a tuple is a globally understood concept. The last two examples suggest a similar capture model to that of lambdas, which provides consistency.
Interesting consistency, considering that &bar means address of bar
everywhere else, but reference to bar
in lambda captures.
& means "reference to" in argument declarations, method declarations, lambda captures and structured bindings. It seems to me that a tuple (the arbitrary chosen example) is merely conceptually the corollary of a structured binding (although I do appreciate that tuples came first). Therefore to me the notation seems consistent in this case. However, I am not arguing for a particular notation, merely providing an off-the-cuff example of it.
As for the confusion due to the use of & to also mean "address of", I would have to refer you to Mssrs Stroustrup, Kernighan, Ritchie
et.al. for a rationale. I confess it was before my time. I've only been writing C++ since '98.
> Performance:
> Expression through library templates means two levels of translation of intent. One from user intent to expression in terms of existing library code and (sparse) core language features. There is plenty of opportunity for missing concepts in the language to limit the quality of that translation.
> On the other hand, a keyword with code generation behind it means that a users’ specific intent can be translated into optimal code every time. Furthermore, as compiler technology improves, that translation can be improved, improving every program upon recompilation.
> Of course this is partially true of libraries, but the library still suffers from not having access to direct code generation with knowledge of the absolute intent of the programmer.
I don't quite see what the "plenty of opportunity for missing concepts
in the language" might be, and how
make_unique leads into any less-optimized code than writing the same
with operators and sigils does.
I was under the impression that you were asking about my general rationale for preferring the creation of keywords to describe common concepts in the language rather than library types. It might be that I misunderstood. If you did mean what I thought you meant, then focusing on specific operations where there is no specific performance benefit immediately obvious today would seem to be to be confrontational. I will put it down to a misunderstanding.
> Further:
> Many modern library features rely on compiler intrinsics - from the programmer’s point of view these are required but undocumented language extensions. This is untenable at scale. Better, in my view, to have no intrinsics and simply extend the language to include these obviously essential features. Once that is done, why bother with the complication of a library? Make a tuple a compiler-supported type. Provide class reflection as a language feature. Then it can be easily documented, maintained and shipped with no secret interdependency between compiler and standard library.
Things like tuple and make_unique don't rely on intrinsics. Wrt. "why
bother with the complication of a library?", why bother
with the complication of every compiler?
Again, std::tuple may or may not rely on intrinsics today, that is not the point. We know that a growing number of library constructs do. To me this interdependency between library and non-language-but-otherwise-necessary compiler interface seems like the worst of all worlds.
Why bother the compiler writer? Because compilers are few and programmers are many, so embedding best practice into the implementation of the compiler seems to me to provide best bang for buck in terms of disseminating excellence when transforming human intent into machine instructions. In addition, the compiler has the best possible view of the situation and is therefore the most informed agent in the compilation chain.
A few years ago, I remember that there were laments about it being "impossible to implement std::vector with compliant code". One answer to that (the approach taken) is to supply library tools (backed by compiler intrinsics in the case of clang I believe). Another is to simply accept that vector is so useful and necessary a noun that it ought to be part of the language.
I appreciate that positions such as this have a tendency to ignite religious wars in the C++ community. You don't have to agree, but if you are going to engage with me I would ask that you consider the entirety of what I write, and understand that it is written in good faith.