5 ms·
Yes, testing is Zig's answer. But that quote is right. Testing doesn't achieve the same kind of systematic prevention of memory bugs that rust does. (Or GC base
by josephg 1y ago
Yes, testing is Zig's answer. But that quote is right. Testing doesn't achieve the same kind of systematic prevention of memory bugs that rust does. (Or GC based languages like Go, Java, JS, etc.).
You can write tests to find bugs in any language. C + Valgrind will do most of the same thing for C that the debug allocator will do for zig. But that doesn't stop the avalanche of memory safety bugs in production C code.
I used to write a lot of javascript. At the time I swore by testing. "You need testing anyway - why not use it to find other kinds of bugs too?". Eventually I started writing more and more typescript, and now I can't go back. One day I ported a library I wrote for JSON based operational transform from javascript to typescript. That library has an insane 3:1 test:code ratio or something, and deterministic constraint testing. Despite all of that testing, the typescript type checker still found a previously unknown bug in my codebase.
As the saying goes, tests can only prove the presence of bugs. They cannot prove your code does not have bugs. For that, you need other approaches - like rust's borrow checker or a runtime GC.
- throwawaymaths 1y agostatic code analysis tools can also do it. there's no reason why the borrow checker must be in the compiler proper.
- alpaca128 1y agoThere's also no reason to have a separate borrow checker if it could just be integrated in the compiler. When a compiler has a borrow checker that means the language was already designed to enable borrow checking in the first place. And if a language can let you do borrow checking why would you use a separate tool?
- josephg 1y agoAlso it’s a great way to make sure every library in the ecosystem passes the borrow checker.
- throwawaymaths 1y agowhy do you expect compile time static analysis to fail at this? unless youre loading a precompiled asset?
- josephg 1y agoI don't. I think compile time static analysis is great. Upthread you said this: > there's no reason why the borrow checker must be in the compiler proper. On a technical front, I completely agree. But there's an ecosystem benefit to having the borrow checker as part of the compiler. If the borrow checker wasn't in the compiler proper, lots of people would "accidentally forget" to run it. As a result, lots of libraries would end up on crates.io which fail the borrow checker's checks. And that would be a knock on disaster for the ecosystem. But yes, there's nothing stopping you writing a rust compiler without a borrow checker. It wouldn't change the resulting binaries at all.
- throwawaymaths 1y ago> lots of people would "accidentally forget" to run it yeah, like how the sel4 guys accidentally forget to run their static analysis all the time. You put a badge on CI. If you "forget to run" the static analysis, then people get on you for not running it. Or people get on you if you don't have the badge. Just like how people get on people for not writing programs in rust.
- josephg 1y agoQ: If we can get men on the moon, why is my lawnmower such a piece of junk? A: The engineers who got us in to space didn’t design your lawnmower. The SeL4 team won’t forget to run their static analysis checks. But most people aren’t at their level. Most people just want to get on with it. The borrow checker is a pain in the neck to learn - and if it were optional, you better believe lots of people would avoid it forever. I may well have been in that camp too - I found it really hard to get my head around it! If you want a modern C-like language without rust’s borrow checker, Zig or Odin is probably a better bet. They’re both fine languages. > Just like how people get on people for not writing programs in rust. Who? Where?
- throwawaymaths 1y agobecause it gets it out of the fast path compile cycle. do you need a borrow checker for `ls`? Probably not. don't use it. do you need it every time you work through intermediate ideas in a refactor? probably not. just turn it on in CI.
- steveklabnik 1y agoThe borrow checker is very fast.
- throwawaymaths 1y agocomputationally. But it slows down the programmer. It is not a zero-cost human operation. If it were, we wouldn't need computers to do it.
- steveklabnik 1y agoI don’t think it slows me down, it speeds me up. It’s well known that surfacing issues earlier in a process saves time compared to later in a process.
- alpaca128 1y agoThe borrow checker is not the slow part of the Rust compiler and lets me avoid bugs, why would I not always want to use it? And if you put the borrow checker in the CI you massively increased the latency between writing the code and getting all relevant feedback from the compiler/tooling. This would do the opposite of what you intended.
- throwawaymaths 1y agoYou don't have to query all checks at all times. You only have to borrow check when you pr to main. What is the sum latency of the coder dealing with conceptual problem of satisfying the borrow checker at every stage during an arduous refactor where they don't fully have the destination model in mind (and might want to try things out only to discard them). Versus, just ignoring it, seeing how the chips fall, and fixing ownership errors in one or two passes at the end once you've settled om the code structure? Of course you don't have to take the full round trip-to-someone-else's-computer latency either. If you can run it in CI, I presume you could run it locally too, and borrow checking is not particularly slow for the computer. You're also not (because one can't) quantifying the problem of a developer getting exasperated and saying, fuck it, it passes the borrow checker, good enough, instead of actually taking the time to make their code legible first and then making sure it is memory safe. This absolutely happens.
- tialaramex 1y ago"But seatbelts would also work if everybody was just choosing to use them rather than us mandating their fitment and use, so I don't understand why facts are true" Amusingly this is even true for the linter, nobody ran the C linter, more or less everybody runs the Rust linter, the resulting improvement in code quality is everything you'd hope. All humans love to believe they're above average, most are not and average is by definition a mediocre aspiration. Do better.
- throwawaymaths 1y agowhat the hell are you talking about. if you are writing security conscious software you should turn on a static checker and proudly show a badge that says "this code is memory safe". if youre writing a custom data pipeline to be used in a niche scientific field where the consumers are you and anyone that wants to repro your pipeline, and everything is in arenas, who the fuck cares. don't bother with static analysis.
- josephg 1y agoIf everything is in arenas, lifetimes get much easier. But, the borrow checker doesn't just check lifetimes. It also checks ownership, and that variables either have a single mutable reference or immutable references. The optimizer assumes those invariants are maintained in the code. Many of its optimizations wouldn't be sound otherwise. So, if you could compile code which fails the borrow checker, there's all sorts of weird and wonderful sources of UB eagerly waiting to give you a really bad day - from aliasing issues to thread safety problems to use-after-free bugs. The borrow checker has been around forever in rust. So I don't think anyone has any idea what the implications would be of compiling "bad" code.
- throwawaymaths 1y agoPoint being, there are many many individual programs where none of those things you talk about exist. So why not have a programming system where you can actually turn those things off for development velocity. I'm rejecting the idea that "opt-in" is bad. Opt-out is of course better, but "no choice" is not good.
- saagarjha 1y agoBecause you're always going to write some code that the tools can't reason about.
- throwawaymaths 1y agothats true for rust too (hence "unsafe")