If option A has 20 defects and option B has the superset of 25 defects then option A is better—the fact that option A has defects at all is completely besides the point with regards to relative measurements.
If option A has 20 defects and option B has the superset of 25 defects then option A is better—the fact that option A has defects at all is completely besides the point with regards to relative measurements.
People have been fighting this fight forever. Should we use static types which make it slower to iterate or dynamic types that help converge on error-free behavior with less programmer intervention? The tradeoffs have become clearer over the years but the decision remains as nuanced as ever. And as the decision space remains nuanced, I'm excited about languages exploring other areas of the design space like Zig or Nim.
Yes. If you change the entire premise of my example then things are indeed different.
Rust eliminates some defects entirely. Most other low-level languages do not. You would have to use a language like ATS to even compete.
That’s where the five-less-defects thing comes from.
Go down to ten effects? What are you talking about?
> Rust eliminates some defects entirely.
Is really a true premise, and to the extent it is true, is not a clear to me that it makes Rust better or safer than languages who don't eliminate this class of bugs.
Unsafe exists, is widely used, and importantly is used in places where the hairiest versions of these bugs tend to live anyways.
For safe code, I think it's clear that what we as programmers really care about is "how much does the language reduce the number of defects weighted by severity". If Rust reduces the number of memory bugs but increases other types of bugs due to increased complexity, that might not be a net win.
Personally my guess is that Rust is a net win in this regard, but I don't think we have any evidence of that.
I've worked in heavily monadic Scala codebases where changes in object structure require minor refactors due to strict typing in the codebase. Changes that could be small in other languages would necessitate changes in our monad transformer stacks and have us changing types throughout the project. This eventually lead to engineer anxiety ("small changes take forever so I'm not willing to work on this codebase and explain to my manager why a schema change is taking so long") and aversion to project ownership.
This codebase did materially have fewer defects than other, looser, codebases my team worked with. We got paged fewer times for this codebase than others. Unfortunately, other than a handful of engineers who loved working with monadic FP and were also busy, nobody wanted to touch the code and once the original authors left the team, the codebase went untouched. You could make the case that management should have let these engineers take more time to make these changes but in the meantime, other teams at the company built up high reliability ways of working in other languages and paradigms with higher velocity and similarly low defect rate.
Defects alone aren't everything. You need to look at the big picture.
> you don’t ever have to even think about those kinds of things as long as you trust the compiler and the Unsafe code that you rely on.
Forgive if I don’t give the lawyerly disclaimer in all of my follow-up comments.
Yes, you have to be able to trust the Unsafe code that you depend on.
200+ memory safety errors were found in rust crates: https://www.infoq.com/news/2021/11/rudra-rust-safety/
I love rust, I think there's a good chance zig in its current state isn't the answer, but saying rust is totally memory safe is wrong. You drop into unsafe and people make the same errors C/C++ devs make.
In C/C++ world, _everything_ is unsafe, so you can't even limit your exposure in the safer parts because you can do unsafe operations anywhere.
> you don’t ever have to even think about those kinds of things as long as you trust the compiler and the Unsafe code that you rely on.
Your comment is not some kind of gotcha. I can’t be bothered to give the long-form disclaimer in all of my follow-up comments. Read the context.
I personally am not interested at all in abstract discussions about sets of errors. Reality is much more complicated, each error needs to be evaluated with regards to the probability of causing it and the associated cost. Both things vary wildly depending on the project at hand.
Fair.
> I personally am not interested at all in abstract discussions about sets of errors.
Abstract? Handwaving “no silver bullet” is even more abstract (non-specific).
I have absolutely no faith that, in a future where Zig is popular, it will remain so. "well it passed our unit tests and it didn't fall down when we fuzzed it, so lets squeeze a couple free % extra perf out of it and ship" already in this post we have people talking about how safer mallocs or sanitizers are too much of a hit to expect people to use in the wild.
Only if "defect count" is what you care for.
What if you don't give a fuck about defect count, but prefer simplicity to explore/experiment quickly, ease of use, time to market, and so on?
I might still want Zig just fine. E.g. because I know C well, and it's a better C. Or because of the ease of interfacing with C/native libs. And several other reasons.
Zig allows custom allocators pretty much everywhere, right? Would it be impossible to provide it with a GC-based allocator for increased convenience at the cost of a little performance for programs (or parts of programs) where convenience is preferred? Perhaps libgc could be an inspiration here.
I probably can "beat that", because e.g. breaking things into functions increases simplicity and being able to explore/experiment quickly.
Whereas eliminating defects with a type/lifetime checker you need to hand-wrestle, not so much.