6 ms·
Interesting point. I think I've been feeling this lately as a desire to have, basically, smarter compilers. It's actually incredible to me when I think about ho
by l_t 8y ago
Interesting point. I think I've been feeling this lately as a desire to have, basically, smarter compilers. It's actually incredible to me when I think about how many minutes of human thought are wasted among myself and my peers to informally verify facts about our programs.
Obviously, types and tests help. But it's astonishing how much incidental complexity creeps into one's everyday work with our current tools. Under most circumstances telling a computer to do something shouldn't be that much harder than telling a human to do it (assuming a concrete grammar and shared vocabulary).
- dhimes 8y agoI find it helpful to think of it as teaching a computer to do something rather than telling it to.
- mlthoughts2018 8y agoI’ve programmed professionally in Haskell, Scala and Python in large projects across several jobs. In my experience, the compiler is rarely helpful at catching bugs. Most bugs, whether in a dynamic typing language or otherwise, are behavioral bugs that occur at runtime without generating explicit runtime errors, just incorrect but uninterrupted behavior. I always heard people make grandiose claims about Haskell, like if you get your program to compile, it’s very likely to be correct and run without error. I’ve emphatically never found that to be true. The types of bugs that compilers can help with are very simplistic most of the time. Requesting a method or attribute that doesn’t exist, typos, confusion about arguments passed to a function. In dynamic typing, you also solve these same things in a super cheap and low effort way with unit tests. Additional behavioral unit tests are where real effort becomes required, and these are needed in any paradigm. Compilers are also not free. My experience with the Scala compiler for example was awful. It is so incredibly slow to compile that I absolutely would rather give up type checking and just use some cheap unit tests to have a much faster development cycle. When you make 1 or 2 small changes and even a smart incremental compiler setup like zinc needs to recompile 30 code units and it takes ~ 3 minutes before you can run tests, this is maddening, and the cycle repeats the whole time you’re working, so it’s this constant extremely disruptive expense. I’ve had similar thinga happen in legacy code bases with Haskell too.
- dope99 8y agoI think most bugs are that kind that the compiler can catch. But yes absolutely a program can compile and be dead wrong. I’m writing a regex engine and lol at types saving me from all the mistakes I can make with building and transforming finite automata. I’d still much rather have a slightly slow compilation than verify types in my head every time I’m in that area of code, or writing unit tests for every configuration of code which basically just validate I haven’t returned any nulls. Typed compilation may take time, but it results in faster running programs. And unit tests also take time. I find the errors generated by a type checker come quicker and give more useful diagnostics for deep areas of the code.
- mlthoughts2018 8y agoMy experience has been the opposite. Compilers are not just a little slow, but introduce a significant slowdown for every read-edit-test loop, which adds up to such huge productivity losses that any small gains from the compiler catching typo-style / wrong arguments sorts of bugs is totally erased.
- dope99 8y agoI’m not arguing here but honestly don’t know: how can interpretation be faster than the checking step of compilation? Maybe code generation takes more time, but Rust has ‘cargo check’ which only typechecks. Parsing is basically a wash between compilation and interpretation. Dynamic types still need to be resolved for the tests to run. So why would interpretation be faster? I’m working through a compiler book and would love to know.
- ghettoimp 8y agoI think mlthoughts2018 may be saying that he finds the advantages of a good "read-edit-test loop" to be more valuable than a compiler that catches type errors? It is certainly valuable. A good REPL is completely fantastic for prototyping and debugging. Being able to change how your program works while it's still running and has all its data loaded is great compared to a classic edit-compile-run cycle where you've got to get your program's data re-loaded each time. But I don't see that this has much to do with compilers versus interpreters, or even really dynamic versus static type checking... - There are REPL-based environments with integrated compilers, and there are compiled languages with REPLs bolted on top. - Good REPL support is surely more challenging for languages with strong static typing. After all: what does it mean to redefine a type? what happens to the functions that are using the old definitions? what happens to the instances of that type that are already alive in your program? But these problems all exist in dynamic languages too, it's just easy there to sweep them under the rug by treating them as yet more run-time errors.