https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in...
Basically D just needs that big break to actually get things done. There are some absolutely brilliant people working on D but there's only so much sweat people will donate (some people are paid but I imagine rust probably has upwards of a hundred full time staff given that Mozilla and Microsoft use it in an official capacity)
Which is nice but it's still missing some of Rust's features.
No. You need to "annotate" a mutable binding since bindings are immutable by default. But that also means that immutable bindings (ie the vast majority) does not to be "annotated". And even when you do need to, you literally just add the keyword `mut` as in `let mut foo = 42;`.
> and you often need to splatter confusing lifetime annotations all over the place. It adds a big learning curve to the language.
Again an extreme exaggeration. There are a few cases here and there where you need lifetime annotations, but most often the compiler simply infers them for you, allowing you to elide them completely. Specifically, you only need to do it yourself when it's ambiguous from which input(s) the output is derived.
EDIT: What's really relevant is that you can look at a Rust type, and tell whether it's shared, mutable, or owned; this is what Rust's borrow checker derives its power from. Likewise, Haskell's type system derives its (equally amazing) powers from the fact that you can look at a Haskell function's type signature, and tell what kinds of side effects it has. (Sometimes people think that Haskell functions don't have side effects in the sense that they never mutate anything. This is wrong; Haskell has mutable arrays in its standard library. Rather, it's that all side effects are reflected in a function's type signature.) https://hackage.haskell.org/package/array-0.5.4.0/docs/Data-...
I write Rust code for work, and we have a large codebase. We manage it pretty well, but there are definitely still innocuous looking changes that require adding lifetime annotations all over the place to avoid confusing error messages.
Rust is my favorite language by far (I get the impression you like it too and are defending it). I think the costs of its borrow checker are worth it, but they are significant costs.
I have not utilized tagged unions outside this type so I'm not one to comment on any deficiency.
And Rust's borrow checker can give very strong guarantees that aren't present in any other mainstream language that I'm aware of. In Rust, you can pass mutable references to large data structures between threads, without copying or GC or any type of runtime checking (e.g. Mutexes), and the borrow checker will guarantee that you can't have a data race (data race = concurrent read & write). In comparison, I believe that in Haskell you'd do this with GC, in Java you'd do it with GC and a mutex, and in C you'd do it very carefully.
As another example, in Java if you modify an ArrayList while iterating over it, you'll get a ConcurrentModificationException. In Rust, you can't. The borrow checker won't let your program compile.
The cost of this borrow checker is huge: every reference in every program needs to be annotation with whether it's shared or mutable, and you often need to splatter confusing lifetime annotations all over the place. It adds a big learning curve to the language.
I don't know the details of D's ownership system, but it's not like Rust's borrow checker. Does someone who does know more want to describe it? I've just seen the language reference page here, that describes "scope" and "returns". https://dlang.org/spec/memory-safe-d.html