Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

Rust also has features which interact in subtle and surprising ways. Generics and operator traits bumping into the "coherence" rules is my personal pet peave. I doubt any user would have predicted that interaction, and even though the compiler gives a detailed pointer to why, it's cold comfort.

Honestly, after hating C++ for years, trying to use Rust made me appreciate more about C++. I wish someone would make a language which took the best parts of both.



sort by: page size:

I'm surprised C++ doesn't support it. I wonder how rust does (with Traits)

Compile-time duck typing :) To be fair, C++ templates have a similar problem. Rust nails this one with traits, I think.

This is pretty much how every language does generics except C++, so it's not actually an issue with Rust.

I've been writing rust recently and trying to figure out how to write generic traits using higher ranked trait bounds with understanding variance sufficiently to know I'm not creating a soundness hole is much more difficult for me than writing C++. It's like all the template hackery madness you needed to resort to to do anything mildly interesting in C++98, except it's in the core idioms of the language.

The easy examples involve operator overloading.

Some more subtle would involve template dispatching according to properties of the types operated on.

But just run down the list of features supported in C++, and not in Rust, and think about how they could change how a library interface or implemention would look. Most C++ features are meant for people writing libraries.


Hmm , I’m no kernel writer but I don’t think trait’s necessarily offer anything in rust over C++ where I’d use polymorphism with abstract interfaces.

When I’ve written lower level components the things that have really been godsends outside the safety features are things like enums (much more powerful than C/C++ unions/enums and much more ergonomic than variants).

And even though I said traits don’t offer too much more than C++, one thing I think they do really offer is when combined with generics. Rust generics let you define trait requirements better (though not as extremely flexible) as C++ concepts/constraints.


You're conflating traits with generics. Generics exist without traits, and in Rust they are more closely aligned with C++ templates than anything else, since they are implemented via monomorphisation, whereas in Haskell they are not.

Regardless, Rust is not "patterned" after a single other language. It's influenced by many langauges, so it makes no sense to say that one feature is just copied straight from a specific other language.


Because Rust’s generics are patterned after Haskell’s (traits are dual to type classes), not C++’ templates.

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.


Rust has traits on structs instead of using inheritance. Aka composition.

I like rust a lot but when you get into errors because some deeply generic trait can't be matched, believe me, the compiler's messages are cryptic :-)

Rust generally uses function/method polymorphism based on traits (aka type classes), that's far less prone to overuse and abuse than overloading in C++.

I kind of get that feeling, too.

Rust uses "traits" to do both generic-like things and inheritance-like things. It's not clear this was a win. The result seems to be a system which does both badly.

Rust generics are very restrictive. They're not at all like C++ generics. It's not enough that every operation on a type needed by a generic be implemented. The type has to be part of a single trait that provides for all those operations. It's like C++ subclassing. So generics over types defined by others can be impossible to write in Rust. This has no safety benefit, since generics are resolved at compile time and all safety tests can be made after generic expansion.

Traits and fixed array bounds do not play well together. This is considered a bug, and it's been a bug since at least 2017. Generic parameters can only be types, not numbers. This led to a horrible hack involving a Rust crate which has types U1, U2... U50 or so, so small numeric constants can be bashed through the Rust type system.

Not seeing the benefit of all this.

I have to go struggle with another non-helpful "lifetime `'static` required" message from the borrow checker now.


I think you're comparing Rust to a language with ad-hoc polymorphism like C++ (where you pay for the somewhat simpler signatures with confusing template instantiation errors), and I'm very glad we didn't follow the C++ route. Rust's generics are very similar to those of Haskell.

The only major generics-related issue that is getting some significant thought is the ability to have the automatically derive the return type on top-level functions, which is not something that is common in other statically typed languages (only C++ and those with whole program type inference, which has its own set of drawbacks).


Yeah, when reading this I was wondering if Rust has sealed traits like Scala, and also structural typing.

The extreme degree of shared syntax and shared semantics with Scala was really surprising to me.


Operator overloading in Rust is less flexible than in C++, so there are fewer possibilities to mess it up.

Overloading is done indirectly via specific named traits which enforce method signatures, invariants, immutability rules. Assignments and moves can't be overloaded. Borrow checker limits what indexing and dereferencing overloads can do (hardly anything beyond pointer arithmetic on immutable data). Comparison operators can't be overloaded separately and can't return arbitrary values (like C++ spaceship operator). Generic code has to explicitly list what overloads it accepts (like C++ concepts), so even if you create a bizarre overload, it won't be used in generic code.


Generics and compile time computation. I think Rust should achieve feature parity with c++ templates and constexpr.

Rust has traits (similar to interfaces). And limiting to single inheritance like Java/C#/etc. makes things quite manageable.

Rust traits are similar to features in many different languages: Swift protocols, Haskell type classes, Scala traits (when used as implicit evidence), even Go interfaces (in an approximate order from most to least similar). It's not the OOP way of doing things, but it's not senseless nor is it uniquely different.
next

Legal | privacy