> The most crucial thing to understand is that C++ 0x Concepts were a significantly more powerful feature than the C++ 20 Concepts you got.

This makes a bit more sense than what you originally wrote.

Though regardless if C++ 0x concepts were more powerful, C++ 20 concepts as they exist today are strictly more powerful than Rust traits. You admit that yourself when you say that Rust traits cannot model disjunctive bounds. They certainly can't do arbitrary boolean predicates or negation.

That means that Rust's trait system cannot implement compile time type checking rules that C++ 20 concepts can today. You cannot encode entire sets of logic in the type system that you can in encode in C++ (or other) languages.

Features like disjunctive logic may not be able to be proved "sound" for things like borrow checking but that's not the point or intent. The point is that you can use arbitrary boolean predicates in inventive ways. Hence my original comment about "seeing where C++ concepts go".

> Even though I emphasised this, you seem to have muddled them together to produce what you're calling "C++ x0 concepts" in several places, which is not actually a thing.

True, my terminology got muddled. Trying to follow your terminology and (odd) backstory about C++ 0x concepts was confusing.

You are incorrect about how C++ 20 concepts work and that makes it more confusing.

There are lots of resources showing that C++ concepts are implicit and don't need to be explicitly instantiated. Take this Rust comparison: https://mcla.ug/blog/cpp20-concepts-are-not-like-rust-traits...

While Rust traits force a "closed" system (to be imprecise) that's easier to prove soundness on upfront, that doesn't make the type system more powerful. It may make it more useful in some people's view. That's a pretty big distinction.

> No, it would be true for C++ 0x Concepts but those never existed beyond a draft document. It does work for Rust traits as you say but you can't do it for C++ 20 Concepts.

Err, no that's incorrect as you can easily check in any of the references I gave. C++ concepts as they exist allow you to call concepts if they fulfill the concept.

In Rust you must own either the trait or the type in order to implement said trait for that type. This is a widely known and deliberate limitation of the Rust trait system. It has some benefits, but is also leads to significant "trait bloat".

The "orphan rule" doesn't exist in C++ 20 concepts. It's an intentional Rust design decision: https://rust-lang.github.io/chalk/book/clauses/coherence.htm...

> It is of course possible to write a Rust trait for something as useless as "any numeric type regardless of what kind", that's what the Num crate's Num trait is. Because Rust's traits have semantics, useless traits reveal themselves - you can't do much with something whose only decisive property is that it's numeric in some way.

I don't really follow what you're trying to say here.

In contrast, I do find it very useful to define default algorithms for any numeric type that matches. It's a core part of C++ numerical libraries.

However, I get that this would be fairly pointless in Rust because you can't do much useful with it without things like generics specializations being stable.

> The "HasPower" example is revealing though, lots of people's toy Concepts are like this. They just dictate a morsel of syntax. C++ 20 Concepts are indeed suitable for this, but so is nothing whatsoever, because of C++ template "magic".

This makes no sense. A "morsel of syntax" or alluding to "C++ template magic" make no sense.

Granted C++ template's are amazing powerful, and amazingly difficult to debug.

C++ 20 concepts provide a useful and flexible way to describe compile time type restrictions, while not limiting C++ templates to the purely adjunctive subset of type logic able to be described in Rust's trait system.

> > Everything in Rust traits requires them to be encoded into existing traits.
> What you've written is a tautology. So I can only guess what insight you thought you had here.

It is, I was being lazy but the point I'm reaching for is that using Rust's trait system requires the traits you want to target to already exist and to be implemented for the types in question. Moreover, creating some type-based logic rules using the Rust trait system, requires that logic to effectively already be encoded into the traits (as some combination of adjunctive properties).

This is why you end up with incompatible HAL libraries for various STM32 models, among others. In my opinion it's a very limiting part of the ecosystem.