Live data from Hacker News

C++20 Concepts: The Definitive Guide

thecodepad.com

71–80 of 102 posts

Re: C++20 Concepts: The Definitive Guide

#71
post #25
post #11

Another language-changing paradigm added to C++. I haven't even finished learning the old ones yet. Sometimes I think C++ would be better off if the committee stopped accepting proposals that add new features.

It’s true that C++ is huge but the complaint should be about the lack of epochs that would let us simplify the language instead of about very useful new features such as concepts, modules, or constexpr. If you’re already programming in C++ and you can’t take a few days every 3 years to learn about new additions, you’ll have even more problems with other languages.

> but the complaint should be about the lack of epochs

Rather than something as coarse as epochs, C++ includes a lot of fine grained feature test preprocessor definitions such as (to pick one at random) '__cpp_lib_constexpr_algorithms'.

It's harder to make this work with breaking API changes of course. I assume non-preprocessor versions that work with modules will be available in C++23...and perhaps they will support API changes?

Re: C++20 Concepts: The Definitive Guide

#72
post #10

Earlier quoted context omitted.

One of clang’s stated goals is “expressive diagnostics” See https://clang.llvm.org/diagnostics.html ; that page is not dated, but compares to gcc 4.9, which is from April 22, 2014. gcc also has worked on improving its error messages (most likely because of competition with clang), so that comparison probably isn’t accurate anymore.

The link leads to a 404.

The comment markup parser mistakenly understood the link to include the following semicolon, but you couldn’t clearly see it because the semicolon’s descender hid the underline.

Re: C++20 Concepts: The Definitive Guide

#73

I feel like one of the things a "Definitive Guide" to this feature needs to make clear, and maybe even emphasise, is a key way these are different than say Rust type Traits. Concepts, just like the SFINAE and constrexpr hacks you should discard in their favour, are about only what will compile and you, the C++ programmer, are always responsible for shouldering the burden of deciding whether that will do what you mean…

> I feel like one of the things a "Definitive Guide" to this feature needs to make clear, and maybe even emphasise, is a key way these are different than say Rust type Traits. > Concepts, just like the SFINAE and constrexpr hacks you should discard in their favour, are about only what will compile and you, the C++ programmer, are always responsible for shouldering the burden of deciding whether that will do what you…

The trick is that in Rust the implementer chooses which Traits to implement for their Class while in C++ the Concept chooses what properties it will require and then applies to any classes with matching properties whether that's desirable or not.

So in C++ the fact a Mouse is food::LovesCheese doesn't actually tell me whether the Mouse's programmer has any idea what it means to food::LovesCheese or whether the food::LovesCheese programmer knows about a Mouse. I need to carefully read the documentation, or the source code, or guess. It might be a complete accident, or at least an unlucky side effect.

In Rust the fact a Mouse has the trait food::LovesCheese always means specifically that either (1) the Mouse programmer explicitly implemented food::LovesCheese as part of a Mouse or (2) the food programmer explicitly implemented a way for Mouse to food::LovesCheese. Rust requires that nobody but them can do this, if I have a Mouse I got from somewhere but alas it doesn't food::LovesCheese and I wish it did, I need to build my own trivial wrapper type MyCheeseLovingMouse and implement the extra trait.

Either way as the user of any Mouse, you can be sure that the fact it has food::LovesCheese in Rust is on purpose and not just an unfortunate behaviour that nobody specifically intended and you need to watch out for.

Re: C++20 Concepts: The Definitive Guide

#74
post #37
post #11

Another language-changing paradigm added to C++. I haven't even finished learning the old ones yet. Sometimes I think C++ would be better off if the committee stopped accepting proposals that add new features.

I think there's more to it (changing the language) than you are crediting it. First, you don't have to use the new features (though eventually you'll be reading the code of people who did, so this is only half-valuable). There is new c++11 code being written every day -- in volume (a hard to pin down amount) it's sadly more than 50%. The usage surveys don't really capture this clearly (and it's not clear they could).…

>you don't have to use the new features

But it complicates the compiler, complicates the tools, complicates the error messages,...

Take something as "simple" as operator overloading. If a beginner does a "5"+5, the compiler is forced to respond with "no operator + for the types given, types are: int, std::string" instead of the infinitely more friendly "can't add string to int". I actually _like_ operator overloading, I wish more languages stopped the silly practice of making language-provided primitives somehow sacred and closed-to-extension. But look at how even this relatively straightforward and useful feature ruined the error message.

Part of this particular example is bad error message design. I mean, what are the chances somebody intended to do operator overloading but then forgot to implement the method? It would have been much better to say "Can't add string to int, Did you forget to implement operator+(.. .,...)?". This centers the common case first, then reminds the experienced about what could have happened in their case. But even this might confuse beginner and convince them that "5"+5 is somehow a reasonable thing to say (because it actually is in some contexts) that they just need to get that fabled operator+ from somewhere to make it work, instead of just outright telling them " nonsense, not gonna work".

Extensions are always, inherently, abstractly, a tradeoff. Because even if you are a perfectly spherical coder who doesn't interact with other code in any way, you at least interact with the language tools. And the tools _must_ know all the of the language: instead of just having the luxury to say "sorry mate can't do that" when encountering "5"+5, the editor/IDE/compiler has to spend the cycles to see if it _can_ do that, then report a message that simultaneously says that you can but can't. As the features accumulate and interact, the tradeoff curve increasingly inflect against adding new things.

All of this in the abstract is a fairly balanced argument that applies to any language, the particular case of C++ is much, much worse. C++ have this aweful way of "retconning" new features. I can never put my hands on it, but C# creators practically design a new superset every major version and call it the same name without ever making people angry or afraid that the language is spiraling out of control, but every C++ feature gives me this dark feeling of "is this never ever going to end? how far are you willing to take it?".

Part of that is undoubtedly the syntax, remind me again what language class (regular, context free,..) is C++ syntax? The other day I was fooling around and thought of adding discriminated unions to C++, just a thin syntax layer over a more verbose idiom. The very first thing is to parse the damn thing, but that way lies madness. Because C++ have no agreed-upon, guaranteed formal grammar. There is a grammar online but it's gargantuan and was written by one man, there is a grammar in the standard but it's gargantuan and the standard says it's there for illustration only, there is a grammar (implicitly) in the source code of any working parser but it's gargantuan and full of hacks. So for all practical intents and purposes, C++ has no formal grammar. Think about that for a minute, a formal language that has no formal grammar. It's the bare minimum any formal language can have, and yet you can't do it safely because of the massive, beast-like bloat that is that language.

Re: C++20 Concepts: The Definitive Guide

#75
post #53

Earlier quoted context omitted.

The less you use the new features, the less benefit you get from them. You could stick to K&R C and get no benefit at all, but that would be equally as foolish as what you are doing. The new features are there to improve your experience, and to make your code more reliable. When you have a choice between old and new, new is usually better. Sticking to K&R, you would have as many bugs and crashes as other K&R code. St…

I'm not sure how you drew a line from my discussion of c++98/11, to K&R C.

They are all points on a continuum. There is no more wisdom in stopping at 98 or 11 than in stopping at K&R.

Re: C++20 Concepts: The Definitive Guide

#76
post #40

The most important thing to say about this "definitive guide" is that it delays to the end presenting the overwhelmingly most important detail about Concepts: how to use them. The right place to put a concept name, in production code, is in place of "typename" in a template definition, or even better in place of "T" in the function argument declaration. That is, instead of template T add(T a, T b) requires addable (…

> Most often it is not necessary, and not wanted, to enforce a and b having the same type. That really depends on what you're trying to do. Presenting these two different declarations as somehow equivalent is very misleading and I'm glad that the author didn't do that.

They are not presented as equivalent, but as a choice.

The author's failing was in presenting neither of them until long after they were due, and presenting thoroughly inferior alternatives in the meantime.

Re: C++20 Concepts: The Definitive Guide

#77
post #44

Earlier quoted context omitted.

Scott Meyers was never a production coder. His schtick was teaching, and he got tired. The additions since he bowed out improve the experience of production coders.

He got tired because of the insane complexity of the language, and in the video I linked he supports his complaint with extensive and damning examples.

His difficulties are characteristic of someone not seeking solutions to actual daily engineering problems, and instead getting lost in a maze of language lawyering.

If you approach features in terms of how they can be useful when coding, almost all of his difficulties never arise, or are easily sidestepped. For working coders that becomes second nature.

Re: C++20 Concepts: The Definitive Guide

#78

I feel like one of the things a "Definitive Guide" to this feature needs to make clear, and maybe even emphasise, is a key way these are different than say Rust type Traits. Concepts, just like the SFINAE and constrexpr hacks you should discard in their favour, are about only what will compile and you, the C++ programmer, are always responsible for shouldering the burden of deciding whether that will do what you mean…

> I feel like one of the things a "Definitive Guide" to this feature needs to make clear, and maybe even emphasise, is a key way these are different than say Rust type Traits. > Concepts, just like the SFINAE and constrexpr hacks you should discard in their favour, are about only what will compile and you, the C++ programmer, are always responsible for shouldering the burden of deciding whether that will do what you…

First off, we should be clear what we mean by "guarantee". When you're talking about Rust, "guarantee" means "the compiler enforces this in an ironclad way, such that the programmer cannot mess it up" (generally with the implied caveat that we assume unsafe is not used). C++ programmers generally use "guarantee" to mean "the standard says you should follow these rules", because as the language is not type-safe the compiler is in general unable to enforce much of anything that is interesting, making the Rust sense of the word "guarantee" not a particularly useful concept in that language. Confusion between these two meanings of "guarantee" (along with related concepts like "safe") has resulted in a lot of misunderstandings over the years.

Bearing this in mind, neither concepts in C++ nor traits in Rust guarantee any semantics in the Rust sense of the word. In the C++ sense of the word, C++ concepts do carry guarantees, in that the spec says what they should do. But, in this sense, so does Rust: PartialEq [1], for example, has semantic requirements spelled out in the documentation. In my mind, the difference is that Rust programmers tend to program defensively, not trusting programmers to get things right that the compiler doesn't enforce. Thus you see a lot of conversations along the lines of "what if the implementer of trait X does something weird?" in the Rust space. This may give the impression that Rust traits don't have a clear and consistent semantics associated with them. But that's not right: the implementer of PartialOrd, for example, is absolutely expected to implement a proper partial order, as explained in the documentation. A specification for Rust could specify associated semantics for those traits, just like in C++.

[1]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html

Re: C++20 Concepts: The Definitive Guide

#79

Am I going insane or does the following does NOT work(?): template T mul(T a, T b) { return a b; } template T mul(T a, int b) { std::string ret_val{std::move(a)}; a.reserve(a.length() b); auto start_pos{a.begin()}; auto end_pos{a.end()}; for(int i = 0; i I knew it looked odd to me for some reason...I had to re-write it as follows: template T mul(T a, T b) { return a b; } template T mul(T a, int b) { std::string ret_v…

Four spaces before each line will format your code so other people can read it.

Re: C++20 Concepts: The Definitive Guide

#80
post #79

Am I going insane or does the following does NOT work(?): template T mul(T a, T b) { return a b; } template T mul(T a, int b) { std::string ret_val{std::move(a)}; a.reserve(a.length() b); auto start_pos{a.begin()}; auto end_pos{a.end()}; for(int i = 0; i I knew it looked odd to me for some reason...I had to re-write it as follows: template T mul(T a, T b) { return a b; } template T mul(T a, int b) { std::string ret_v…

Four spaces before each line will format your code so other people can read it.

You only need two on Hacker News, not four. https://news.ycombinator.com/formatdoc
Post reply on HN