Hazard pointers are by no means fast, but a single hazard pointer being set per operation on a shared data structure barely registers compared to the cost of the rest of a nontrivial concurrent access most of the time. Scoped threads don't require bumping a reference count on access, either. Concurrent immutable access in Rust requires literally no overhead at all. In the long run, throughput might drop if you have to take a lock on the entire data structure to perform something like a resizing operation, of course, but for many applications this can be completely avoided (and for those that can't, Java isn't much better).
I generally agree with you on GC but, assuming you haven't, I think you would benefit from actually trying to write some of these algorithms in a manually memory managed system. It's really not as hard as you consistently make it out to be in a language like Rust with very precise control over lifetime (which can be exploited just as well for the hazard pointer itself as it can for anything else).
1. The use-case I have in mind is an in-memory database because a. that is a significant part of what I do and am most familiar with and b. because in the age of large RAM, its most effective use is embedding large parts of the database within the application process (whether as an actual product, or replicating some part of a database's functionality ad-hoc). While doing so in an environment without a GC is certainly possible, it is both much harder and/or (depending on the effort spent) less scalable with increasing numbers of cores. I have come to that conclusion after spending many years trying doing that in C++.
2. I have no doubt that Rust -- and I take great joy in this fact -- makes a whole lot of things much easier than C++. But there is also no question that Rust is harder to program than most GCed languages. The question from my perspective, then, is not "why not do it in Rust?" but "why not in Java?". There is a good answer to that question: Rust is much more suitable than Java (in terms of performance and RAM footprint) when running in constrained environments. But unless you're targeting a constrained environment, why work even a little harder at all?
More generally, I believe that the most efficient form of memory management in unconstrained environments, in terms of both throughput and worst-case latency -- and I've had this discussion on HN with pcwalton -- is an environment that allows three types of memory: stack, scoped arenas (including a permanent scope), and a GCed heap. Real-time Java (RTSJ) provides exactly that. Combining arenas with Rust's beautiful scoped threads is a great idea. I believe that reference counting has no place in such unconstrained environments.
Comments
Hazard pointers are by no means fast, but a single hazard pointer being set per operation on a shared data structure barely registers compared to the cost of the rest of a nontrivial concurrent access most of the time. Scoped threads don't require bumping a reference count on access, either. Concurrent immutable access in Rust requires literally no overhead at all. In the long run, throughput might drop if you have to take a lock on the entire data structure to perform something like a resizing operation, of course, but for many applications this can be completely avoided (and for those that can't, Java isn't much better).
I generally agree with you on GC but, assuming you haven't, I think you would benefit from actually trying to write some of these algorithms in a manually memory managed system. It's really not as hard as you consistently make it out to be in a language like Rust with very precise control over lifetime (which can be exploited just as well for the hazard pointer itself as it can for anything else).
Two things:
1. The use-case I have in mind is an in-memory database because a. that is a significant part of what I do and am most familiar with and b. because in the age of large RAM, its most effective use is embedding large parts of the database within the application process (whether as an actual product, or replicating some part of a database's functionality ad-hoc). While doing so in an environment without a GC is certainly possible, it is both much harder and/or (depending on the effort spent) less scalable with increasing numbers of cores. I have come to that conclusion after spending many years trying doing that in C++.
2. I have no doubt that Rust -- and I take great joy in this fact -- makes a whole lot of things much easier than C++. But there is also no question that Rust is harder to program than most GCed languages. The question from my perspective, then, is not "why not do it in Rust?" but "why not in Java?". There is a good answer to that question: Rust is much more suitable than Java (in terms of performance and RAM footprint) when running in constrained environments. But unless you're targeting a constrained environment, why work even a little harder at all?
More generally, I believe that the most efficient form of memory management in unconstrained environments, in terms of both throughput and worst-case latency -- and I've had this discussion on HN with pcwalton -- is an environment that allows three types of memory: stack, scoped arenas (including a permanent scope), and a GCed heap. Real-time Java (RTSJ) provides exactly that. Combining arenas with Rust's beautiful scoped threads is a great idea. I believe that reference counting has no place in such unconstrained environments.