3 ms·
It was poorly timed and the default GC terrified (C/C++) people. It would've been more constructive for D to focus less on using GC and more on compromises and
by codewright 14y ago
It was poorly timed and the default GC terrified (C/C++) people.
It would've been more constructive for D to focus less on using GC and more on compromises and intermediate stages between fully static memory management and raw malloc/free.
Compromises like reference-counting pointers with various semantics available in Boost.
C++ didn't kill D, Java did. D was never going to replace C++.
Rust is doing a better job of making things like that available (unique pointer, borrowed pointer, etc).
That said, D didn't embrace "pay for only what you use" at a serious level because shutting off the GC basically left you in the wilderness and there weren't many accommodations made for making non-GC operation as good as possible. Rust doesn't seem to embracing that either for the sake of prioritizing safety.
- pcwalton 14y agoRust is embracing optional GC. Almost any use of the GC in the standard library is considered a bug at this point. Also, the GC in Rust is not for safety (as the language is memory-safe regardless of whether you use the GC); rather it's for convenience when you want it. We can't ship a competitive touch-responsive browser engine if the compositor has GC pauses, so making the GC optional is as critical for us as it is for everybody else.
- codewright 14y agoI know the GC is designed to make a lot of task-centric things work nicely. I mean, it's good that the GC is optional and I think Rust is well-designed but you get what I'm saying about "pay for only what you use". GC being optional alone doesn't constitute embracing that mindset. It's a far-reaching sentiment that explains a lot of the stranger design decisions in C++. I'm sure Rust could end up being great for Servo, but there's more to how C and C++ get used than that. It takes a lot of unintuitive design compromises to make a language that's just as suitable in a 4kb RAM embedded device as it is in an HPC cluster. Only a committee of people from very diverse backgrounds is generally going to be able to account for that sort of thing. For better or worse, C and C++'s design-by-committee did result in languages that were capable of coping with a vast variety of extremes, even if it meant giving up a lot of 'niceness' and never really taking safety seriously beyond tooling/testing. "Pay only for what you use" means safety optional, GC optional, dynamic allocation optional, everything. I know you're a very well read and highly experienced programmer and I have a lot of confidence in the Rust-dev team, but you are not replacing C++. You're replacing C++ for Mozilla.
- pcwalton 14y agoI'm curious what in particular in Rust's design that you feel closes off optimization opportunities. "Safety optional, GC optional, dynamic allocation optional" are all true for Rust, for example. I don't feel that we're replacing C++ for everybody, of course. C++ is a very nice language for what it does, and there's a huge amount of infrastructure and an ecosystem built around it. I don't think that we're at an optimization/performance disadvantage relative to C++ in terms of the language design, however. (Compiler toolchain immaturity is another issue, though; currently we aren't really using LLVM to its full potential in various ways.)
- codewright 14y agoYou are willing to do things at runtime that C++ would never countenance. What parts of the runtime are non-optional? It seems like you'd be in a weird and precarious position, as well as lose access to a number of features, if you shut off the GC. C++ doesn't assume the existence of a GC, because it's designed to make manual or semi-automatic memory management as performant or accessible as possible that mode of operation is better accommodated when the time for performance arises. D let you shut off the GC too, except now you were "on your own". What can't be shut-off that happens at runtime? In C++, "pay only for what you use" isn't really a compiler flag (although some things are), it's a core design principle of the language and it was designed from the ground-up for that. Adding a few compiler flags for a mode of operation that wasn't designed for from the beginning isn't really the same thing, no? Further, Rust doesn't accommodate as much variety or control over the concurrency semantics for the sake of promoting the use of tasks. That is unconscionably unacceptable for systems programming where you need to be able to use virtually any approach to concurrency depending on the nature of the problem being solved.
- pcwalton 14y agoIf you don't use the GC, then you can use stack allocation, unique allocation (like std::unique_ptr), arena allocation, or reference counting with smart pointers. You don't give up memory safety; it is still not designed to be possible to have dangling pointers, wild pointers, etc. As an example, I wrote an MP2 decoder that didn't use dynamic allocation or unsafe code at all, and it wasn't particularly unnatural to write in this way. The reason why GC pointers are built into the language is that GC really requires compiler support to do well (with stack maps) and, in particular, to interoperate with the parts of the language that don't require GC in a safe way. You can't just add GC to a language that wasn't designed for it and have it work as well; the best you can do at that point is conservative GC. If you want good GC, that's a decision you need to make early on, and you need to bake it into your language to some extent. (That doesn't mean you need to rely on it though; that's exactly what Rust is trying to prove!) There is very little that is not planned to be able to be shut off, relative to C++. One of the biggest is failure; if your functions fail, then you have to arrange to run all destructors on the stack while your thread exits. (This is similar to C++ exceptions, and are in fact implemented with C++ exceptions under the hood right now, although we plan to change this.) I suppose we could also have a mode whereby we just leak everything on failure to avoid this overhead (basically like -fno-exceptions in GCC; this is pretty much exactly the same tradeoff as C++ offers). I don't think it'd be popular though :)