As of C++20, with "Concepts", that name is not just a placeholder. It means something that enables the compiler to do work for you that Rust cannot. The most trivial of that work is to check that the type provided implements a comparison operator, which mostly affects error messages if you pass a type without, but you can use it to make types pick up a great deal more reponsibility.
It is not often mentioned on HN that whole swathes of functionality modern C++ coding relies on are entirely missing from Rust. Clearly, people can get along without powerful features -- important programs are coded even in C -- but it is a great deal more work. One consequence is that C++ and, to a degree, Rust programs are faster than programs coded in weaker languages, simply because more time is available to pay attention to performance, and any such attention to a library may help many more programs. Weaker languages are simply unable to express usability improvements and optimizations you would like to capture in a library.
> check that the type provided implements a comparison operator
If I understand correctly, this is done with traits in Rust. In this case, the PartialOrd and Ord traits. More elaborate use cases for traits cover things like "is this type safe to send between threads" and "does this type have a statically known size on the stack".
Nathan is talking about std::random_access_iterator which is a C++ 20 Concept, whereas the text in the blog said RandomAccessIterator which was a C++ 17 (and earlier) Iterator "category" now named LegacyRandomAccessIterator which doesn't actually do anything in code and so yeah you could just as well write T.
C++ concepts are just duck typed, whereas Rust's traits have actual semantics.
For example in C++ a float (the 32-bit floating point type) is std::totally_ordered because it has the necessary operators so "quack" - even though of course this type isn't actually totally ordered. If (when) you rely on this sort of promise your C++ program is "ill-formed, no diagnostic required"...
In contrast Rust's 32-bit floating point type f32 is not Ord, because well, it isn't totally ordered is it? NaN. So sort() doesn't work on say a slice of f32, because sort is defined over totally ordered types. You will need to provide an ordering function to explain how you think they're ordered.
C++ had no choice, you can't show up decades late to the party and say "Now we're defining these semantic traits" when there's so much code out there without them. Rust started from a fresh slate. Now, Nathan here (and many like him) would prefer to make a virtue of this necessity.
Once upon a time (before Rust 1.0) Rust did actually have a trait named RandomAccessIterator but it was not well loved because it wasn't practical to do the optimisations you'd actually want (they'd be unsafe, and an unsafe trait here is a big pain point), yet without them it was too slow to be reasonable to suggest anybody use it. So it was abolished.
In practice the slice type [T] is fine here, and the Ord constraint means this sort, like the real one defined on slice, enforces the requirement you'd actually expect.
The Rust sort() implementation is safe here too, unlike the C++ one. It is also stable, because Rust chooses to give you a stable sort, and have people who know they need it write sort_unstable() when that's what they meant, whereas C++ assumes you'd better know exactly what you need or else too bad here's an unstable sort by default...
The exact spelling of correct use of concepts differs from in the example code, but dwelling on it distracts from the valuable point.
It is not correct to say that C++ concepts are duck-typed. They can be used in a sort of duck-typed way, if you choose to. But it is not the normal way to use them. And, using them only as far as Rust's built-in checking can go wastes most of their expressive power, which is unavailable to Rust coders.
> dwelling on it distracts from the valuable point.
You brought up an entirely imaginary situation because you misread the C++ code.
> It is not correct to say that C++ concepts are duck-typed.
The actual mechanism delivered is duck typing. Rust comes with Eq and C++ 20 comes with std::equality_comparable. The former has semantics, Rust only provides implementation of Eq on types which exhibit equivalence, however C++ provides numerous types which match the concept std::equality_comparable despite not exhibiting equivalence, because all it does is check the != and == operators are present.
Would you prefer to say it's "structural typing"? Because the trouble is that it doesn't (and shouldn't) do all of what structural typing does, that's why "duck typing" is the correct phrase.
You are confusing limited use in certain Standard Library components with what concepts are able to do. Duck typing is, as I said, strictly optional. Where that is used in the Standard Library thus far, it improves upon the experience of legacy usage.
Doubling down when you have been corrected adds only heat, not light.
> Doubling down when you have been corrected adds only heat, not light.
All I've done is reported the facts, and, aside from hallucinating concepts in an example which didn't use them you've just insisted the facts aren't true.
I've provided examples like Ord and Eq, and you've provided nothing but denial. Nobody can do anything with that. The reason you find all those Concepts in the Standard Library with duck typing is that it's what Concepts do. If not for the duck typing they might as well just be comments.
Was that all you were getting at? Look at this fancy new comment syntax?
Presumably they intended to say that the (1) cplusplus thing can express something that Rust cannot, and (2) here’s an example of Thing. But then they didn’t properly delineate the two things so that it might come off as if (2) is an argument for (1), but really (1) just talks about Thing in isolation and not as a comparison to Rust... The example was just a standalone example, unrelated to Rust.
If you read what it says, you will see that it says Rust has built-in the most trivial of the things that concepts are used to do, and cannot express the rest at all.
Rust's traits actually reflect semantics, which is what you want, whereas C++ concepts are duck typing and you just get lots of wishful thinking when (too often) that's not enough.
Take a look at Eq for example. Eq is a trait that inherits from PartialEq but has no actual syntactic requirements. It reflects equivalence. Choosing to implement Eq is a claim about equivalence for your type. It has semantics. With C++ concepts you'd have to invent a marker for that purpose, and so C++ does not have any equivalent to Eq. Instead it offers std::equality_comparable which models equivalence but only deliver syntactic matching on the != and == operators like Rust's PartialEq.
It is not often mentioned on HN that whole swathes of functionality modern C++ coding relies on are entirely missing from Rust. Clearly, people can get along without powerful features -- important programs are coded even in C -- but it is a great deal more work. One consequence is that C++ and, to a degree, Rust programs are faster than programs coded in weaker languages, simply because more time is available to pay attention to performance, and any such attention to a library may help many more programs. Weaker languages are simply unable to express usability improvements and optimizations you would like to capture in a library.