Comment by masklinn
3 years ago
> The "leaky abstractions" argument doesn't work for me. E.g. in a Java API you don't commit (at the language level) to the ownership of passed-in or returned mutable objects.
Yep, and so you get all sorts of bugs or defensive code everywhere. For that reason I also have a hard time with one section being
> GC'd code can be more correct
But apparently issues like iterator invalidation and other mutability conflicts don’t rate.
While technically true, I'm not sure that the iterator invalidation argument is that strong in practice. Rust doesn't seem to eliminate those problems, it more moves them around and transforms them into different (though sometimes easier) problems.
We often think that the borrow checker protects us from these kinds of mutability conflict / single-threaded race conditions, by making it so we don't have a reference to an object while someone else might modify it. However, the classic workaround is to turn one of those references into an index/ID into a central collection. In real programming, that index/ID is equivalent to the reference. But while I hold that index/ID, the object can still change, which kind of throws the benefit into question.
In other situations where we only have multiple read-only references, there's not really a motivating problem to begin with, even when coded in other languages that don't also regard them as read-only.
I think the other benefits the article mentions (concurrency benefits, plus encouraging into flatter, cleaner architectures) are a bit more compelling.
I get it about Rust, because Rust really won't let you hide the fact that you're holding on to a temporary reference (GC is an abstraction over lifetime of objects). Borrow checking is also intentionally less flexible about getters (allowing library author to do anything in the getter, but that makes exclusive-mutable getters exclusive over the whole object not just one field). So Java programmers are in for a shock — public fields are encouraged, and APIs have to commit to a particular memory management strategy.
But OTOH not having to worry about defensive programming is so great. Nothing is NULL. Nothing will unexpectedly mutate. Thread-safety is explicit. It's always clear when vectors and objects are passed, copied, or only briefly inspected.
Welcome to ML derived languages with tracing GC, specially pure ones.
Java isn't the be all end all of GC based languages.
I'd think that if you're dealing with immutable data/pure functions GC becomes transparent even in Java ?
1 reply →
Controlling mutation by completely abolishing it is one way to go, but often inefficient. Rust gives you a nice third way.
The author mentions how experienced C developers use some techiniques that drastically improve the correctness of their code.
The same goes with Java: we never use mutability in modern code bases anymore unless we have strong reasons to do so and can keep that mutability as constrained locally as possible.
We also avoid inheritance these days, have your heard about that!? Because yeah, inheritance can be helpful but tends to bite you in the end.
> But apparently issues like iterator invalidation and other mutability conflicts don’t rate.
They don't, because you're using java.util.concurrent when you need data structures that deal with concurrency.
I miss java.util.concurrent terribly when I have to program in any other language. I don't miss Java, but I weep every time I need the equivalent of ConcurrentHashMap or CopyOnWriteArrayList in another language.