Hacker News new | ask | show | jobs
by pcwalton 1757 days ago
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

1 comments

You're correct that Rust's compiler can't guarantee semantics. However because the programmer has to actually implement Rust traits, they can and they should.

That option isn't available to C++ because of how concepts work. PartialEq and Eq wouldn't be different concepts in any practical sense, they would just be a funny way to write a comment, but in Rust they are different traits because even though Eq doesn't add any syntax it does add semantics.

There is one further trick I wasn't going to mention but you've sort of brought it up. Rust's unsafe is partly about taking responsibility for the safe and correct operation of your code. That's a pretty alien thought in C++ although I argue it shouldn't have been, it's clearly too late now. As a result Rust has the idea of unsafe traits. If you get PartialEq wrong, the programmer using your type curses and probably discards it as hopelessly broken, but their program mustn't have Undefined Behaviour as a result by Rust's definition.

However if you implement an unsafe trait like Send wrong, maybe the program now has Undefined Behaviour, as a result (signalled by the unsafe keyword you'll need to use to implement it) you are responsible for making sure your implementation is in fact semantically correct.

This distinction wouldn't mean anything in C++ where not only are your implementations of concepts never required to obey the semantics, but the language doesn't even allow you express that your implementation doesn't obey the semantics, the fact it's a syntactic match means it gets recruited by the concept and too bad.