3 ms·
> This is the misunderstanding. Rust manages to be wonderfully ergonomic without GC. The type system is really the only thing that makes it wordier than C++ Th
by hu3 2y ago
> This is the misunderstanding. Rust manages to be wonderfully ergonomic without GC. The type system is really the only thing that makes it wordier than C++
Thanks for the laugh. Maybe lifetimes/borrow checking syntax got invisible after a while to you. The only explanation.
I'll stop here. Don't have the time nor desire to argue against what seems like passionate opinions.
- timschmidt 2y ago> Maybe lifetimes/borrow checking syntax got invisible after a while to you. I just did a quick scan, in a couple thousand lines of Rust I see two, maybe three lifetime annotations. Nah, not a huge contributor to language verbosity. Most Rust folk seem to work with the compiler's notion of what lifetimes should be, and everything's implicit.
- vlovich123 2y agoLifetime syntax is only more visible if you try to write high performance code. If you wrap everything in Rc<RefCell> or Arc<Mutex> or Box you’ll not see it show up anywhere but you’ll probably still get a performance profile better than tracing GC because time and time again it’s been shown that reliable tail latencies and peak throughputs are generally harder to achieve with a tracing GC. Where lifetimes start to pop up more is in more complicated situations where you are trying to avoid memory allocations and have even higher performing code. And op is correct. In terms of memory safety, Java and C# aren’t as safe as you might hope because significant chunks of the runtime are still in C/C++ (not true for Go) and because of JIT miscompilation bugs (also not relevant for go). Of course JIT miscompilation in theory should be the same as a compiler miscompilation, but in practice it turns out to be worse because you have to maintain consistency between the interpreted and all the tiers of JIT at runtime and in practice humans have a hard time doing that which is why V8 constantly has security vulnerabilities in this area. That’s why GraalVM is interesting because it proposes a JIT design where you only have the compiler implemented once.
- neonsunset 2y agoGo is not magically exempt from constraints other languages are subject to, no matter how much blind faith is put into this mantra. Java has different compiler implementations not all of which necessarily go through interpreter stage. .NET CoreCLR does not have one in the first place (there is technically interpreter code in the codebase but it has bitrotted and is unused). JIT or not does not make it inherently more prone to miscompilation bugs. One thing that Go has going for its compiler is it is a massively simpler design. The downside of that, of course, is much worse compiler output that cannot cope with complex code and is inadequate at high-performance scenarios, where the users of Go either have to try to work around this with goasm or might not even have a solution at all, short of rewriting the component in a different language and praying that the FFI call overhead is low enough for the workload in question. In addition to that, runtime implemented in C/C++ vs Java/C# or other language does not make it inherently safer. It is always a lower-level flavour of the language, where it cannot depend on itself, and with likely numerous relaxations in assurances to stay performant that the authors uphold manually. Even when C or C++ are used - it's usually a limited, focused subset of the language. And it is a bold claim that these runtimes are not extensively tested, fuzzed and otherwise verified against defects before going to production. If you look at bug and CVE history of .NET - pretty much all issues happen in complex "non-core" APIs, often at the unmanaged side provided by operating system rather than .NET itself (the cryptography bits). I can't recall any that are directly or indirectly related to a compiler bugs. I feel like this reply ignores the wider context, which is plain old web dev, where the use of Rust and the decision fatigue that it carries is likely to be misplaced. Just pick C# or Kotlin.
- pjmlp 2y agoLike the Rust compilers partially written in C++.
- consteval 2y ago> If you wrap everything in Rc<RefCell> or Arc<Mutex> ... performance profile better than tracing GC I seriously doubt it. Naively incrementing Ref counters is extremely expensive. Tracing GCs in modern languages are very advanced. The least you could do is try to elide some of the ref increments - but you can't do that in Rust. Also boxing every object is very unpleasant. If you're gonna do that, use a language with reference semantics, like Java or C# > significant chunks of the runtime are still in C/C++ Means absolutely nothing about the safety of the languages themselves. Just because C# has a runtime written in C++ does not mean that you can now magically compile and run use after frees or whatever.
- steveklabnik 2y agoI don’t fundamentally disagree with your points but I do want to point out that in Rust, you have far less recount traffic than in a language that uses reference counting as a GC strategy, because you only increment and decrement on new owners, and not on every access. You can take a regular old &T to the interior of an Rc<T> at any time.
- consteval 2y agoI didn't know this, that's pretty cool. Definitely more manual than what Swift is trying to do with RC elision since you have to then deal with runtimes, but also, I'd imagine much more performant due to a finer-grained nature.
- steveklabnik 2y agoYes, and beyond that, you also have the Rc<T> vs Arc<T> split, so if you're not doing multi-threaded, it's not even an atomic increment/decrement. That said, this is just my intuition here, I've never seen a good benchmark trying to do the comparison, so I don't want to over sell it either. But a lot of times, it's like, "okay I have four threads so I need the refcount to go to four" and then it's just using normal references to actually use the value inside.
- 2y ago