FWIW, as a high performance C++ dev who likes Rust but considers unsafe the biggest issue by far, it's encouraging to see important folk within the project believe there are issues. Too often as a relative Rust outsider it feels like the attitude is "but the unsafe situation is okay because you'd barely ever actually need it!". Hope that unsafe continues to improve!
It's honestly unfortunate that rust has been sold so hard on memory safety, so that when C++ folk don't spend tons of time in memory issues they think rust is pointless.
I don't want rust for memory safety. I want it for things like proc macros, a sane module system, a good and accepted error handling system, destructive move, constrained generics, unified static and dynamic polymorphism, language level customization points, and many more things.
I think there's a bit of confusion here around "value semantics".
No C++ smart pointer has "value semantics", relative to its target T. You can see this because == performs address comparison, not deep comparison, and `const` methods on the smart pointer can be used to mutate the target (e.g. in C++, operator* on unique_ptr is always const, and yields a T&).
This is in contrast to Rust, where Box performs deep equality, and has deep const/mut. In Rust, Box is basically just a wrapper around a value to have it on the heap (enabling things like dynamic polymorphism, like in C++). In C++, the pointer is its own entity, with its own separate equality, and so on.
Const-ness of operations, operator==, and assignment/copying behavior all have to be consistent with each other. For example, if `box` was simply `unique_ptr` with a copy constructor (somehow, and as the table in the blog post basically implies), then you would have that after `auto a = b;`, `a != b`, which obviously doesn't work. This means that the hypothetical `std::box` would have to have its comparison and const-ness adjusted as well. In C++ terms, this isn't really a pointer at all. The closest thing to what the author is suggesting is actually `polymorphic_value`, I believe, which IIRC has been proposed formally (note that it does not have pointer in the name).
Also as an aside, smart pointers are not suitable a) for building data structures in general, and b) building recursive data structures in particular. The former is because meaningfully using smart pointers (i.e. letting them handle destruction) inside an allocator aware data structure (as many C++ data structures tend to be, and even data structures in Rust) would require duplicating the allocator over and over. The latter is because compilers do not perform TCO in many real world examples (and certainly not in debug mode); if you write a linked list using `std::unique_ptr` the destructor will blow your stack.
> The former is because meaningfully using smart pointers (i.e. letting them handle destruction) inside an allocator aware data structure (as many C++ data structures tend to be, and even data structures in Rust) would require duplicating the allocator over and over.
Not quite clear what duplicating means here, but in general most smart_pointers can be constructed with an optional "deleter". Well implmented this would results into the addition one reference (64 bits) field to each instance of the smart_pointer (remove that by using some static member kung-fu but this is hardly worth it).
> The latter is because compilers do not perform TCO in many real world examples (and certainly not in debug mode); if you write a linked list using `std::unique_ptr` the destructor will blow your stack.
This true for all deeply nested structure. Same thing happen in reference counted system like swift.
One can mitigate this by simply controlling the order of destruction.
Duplicating meaning that the smart pointer deleter is going to need a copy of the allocator (or a pointer to it if you prefer, but allocators are already typically pointers). If your container is storing N separately allocated elements, holding them by unique_ptr instead of raw pointer will waste N pointers worth of space with commensurate extra cache use. Fine for homework but not production data structures.
If you control the order of destruction, then you're just manually asking for things to be destroyed, and not actually making use of the smart pointers main functionality. Why use them at that point? That's why I also used the phrase "meaningfully" use them earlier.
Look inside the STL, boost, abseil, etc. You'll very rarely see smart pointers used to implement containers/data structures.
You changed your focus from general data structure to containers specifically which have indeed differents (eg more specialized) design constraints. But still...
> If your container is storing N separately allocated elements, holding them by unique_ptr instead of raw pointer will waste N pointers worth of space with commensurate extra cache use. Fine for homework but not production data structures.
Designing a data structure is an exercise in compromise. You lose space/cache efficiency and gain (exception) safety and ease of use. And of course the lost of space/cache efficiency is a function of both the usage pattern and the size of the store elements...
Calling it "fine for home work" is needlessly dismissive.
> If you control the order of destruction, then you're just manually asking for things to be destroyed, and not actually making use of the smart pointers main functionality.
I disagree with the premise that the main functionally of smart pointers is automatic destruction. Exception safety and ease of use seems more important to me. So using smart_pointer and still controlling the order of destruction is a perfectly valid use case.
But an even more important point is that smart_pointer are designed in way that the length of the management can be different from the life time of resource being managed; By using the reset/release/construct_from_pointer methods. And indeed there are multiple designs when a resource is created unmanaged, then attached to a smart_pointer for a while, then returned to an unmanaged state.
This reflects the fact that the same resource can have different management needs depending on where in the program one is.
> Look inside the STL, boost, abseil, etc. You'll very rarely see smart pointers used to implement containers/data structures.
It doesn't imply any fault in the design of smart pointers.
Smart pointers are resource lifetime management tools, STL containers in general have very simple lifetime contracts... There is simply no need to use them.
It's a pretty drastic assertion (and quite HN worthy) that a whole industry is abusing their developers, based on not even one job, but your impression of a job based on an interview. And assertions like "they expected us never to see our family", because you couldn't take your laptop home? Maybe if you had taken that job, you would have left the office at 5 pm, 95% of the time. Maybe not, of course, but you don't actually know.
I've been working in HFT for nearly ten years, in multiple different roles. I've met well over a hundred developers in the business, have at least a dozen I'd call friends, who are spread over nearly as many companies at this point in time. Most folks have had overwhelmingly positive experiences in the industry. Like anything there are exceptions, but I've seen no evidence of a systemic problem in the field. I know a few people who left my firm to go to Facebook and found it more stressful there, for instance. Certainly, I've worked with very very experienced ex-gamedevs, who would say unequivocally that developer abuse is a far bigger systemic issue in game dev than in finance.
Obviously it's fine to post your take but it should be tempered by the relative amount of experience you have.
I would encourage you to benchmark linear search and binary search on a dynamic array (std::vector) of a million elements. You may be in for a surprise.
I would assume that within unsafe you could simply do the same kinds of shenanigans you would do in C++, e.g. you have a fixed size struct that is just the "header", it's only created on the heap, and it's immediately followed by the variable amount of data which you get access to by casting. If you couldn't do this in unsafe rust this seems like a pretty huge limitation.
It's hard to say. I think a lot of the Rust community actually hails from more of the web world, where security is rightfully a big concern, and the that's where actix was positioned. So maybe with something like HFT it wouldn't be as big of a deal.
On the other hand, very little of the Rust community actually does HFT, or understands the trade-offs. In HFT code, "caching pointers" to just about everything is extremely common, because it's super fast. So you'd be using unsafe a ton. If people got a glimpse of some of the code, I have a strong feeling that some subset would start lecturing (unironically, engineers with a decade of experience in HFT) about safety vs perf trade-offs, and ask "have you actually benchmarked", etc.
Very curious where you work, because there's only really a handful of major places doing HFT (as opposed to algorithmic trading) and haven't heard of Rust being used at any of them.
I think this picture of how HFT and games work doesn't have much connection to how it actually does. In these industries you can't just get all or even most of the high performance stuff you need off the shelf for a variety of reasons. You have to write a lot of it yourself, and likely you'd need to write quite a lot of unsafe code (certainly in HFT, speaking from experience).