> Yeah but typing related bugs which is what static type checkers catch only account for 3% of bugs.
You're stating this as if it's fact and also universal, but I strongly doubt it. Even defining "type-related bug" is hard, because there's a ton of bugs that are not type-related but are much easier to avoid if you're using a good static type checker. For example, stringly-typed values, or switch statement exhaustiveness bugs. Some type checkers, including TypeScript, can eliminate almost all null reference errors when used with strict settings. Then to top it off, types add a bunch of static analysis capabilities you could not otherwise have: for example, you can find accidental dead code because you have an impossible condition that can be proven impossible by types, or more exactly find incorrect usages of library functions, and so forth. There's quite a range of problems and almost none of them are explicitly related to strong typing.
And let's say somehow, this is a universally correct number. That doesn't mean it's the reality faced in front of you. What if you already know the majority of your bugs, as logged today, could be prevented by a type checker?
> You are always going to get more bang for buck by simply writing more unit tests.
Good test coverage is a huge, non-trivial investment for any reasonably large, reasonably complicated codebase. Making all of your code testable in fact impacts how you write code, sometimes in ways that are actually similar to the differences you might make to account for static type systems too.
That said, you should do it! You should do both. Tests catch bugs that type checkers can't, but type checkers offer more than just that, and they catch them faster; typically before you hit save these days.
> Static typing is done primarily for performance and that requires a statically typed language.
I dunno why you're repeating this, people are objectively using static typing for other things. That makes your statement wrong on it's face, because what you're saying is not a matter of opinion, you're suggesting it's "primarily done for performance" and it just simply isn't. Given that TypeScript is one of the most popular programming languages right now, I'd argue this "primarily" categorization is just wrong.
But I think it goes deeper. Like, why does C do static typing? It does not actually need to much. In fact, in an early version of C, the type system was significantly weaker. Struct fields were global: you could access any struct field on any pointer. This is convenient and it doesn't disallow any correct code, but alas nobody is wishing for that to make a return.
I won't even bother getting into functional programming languages, but they exploit types far harder than any of the languages we've been discussing; it's just simply nothing to do with performance.
Maybe C has been trending in the "safer" direction for performance? No. Stakeholders have clearly been improving types specifically for the purpose of preventing classes of bugs observed in the real world. Literally just recently, a great article dropped about array types in Linux, for example:
C++ and Rust use types for a lot of things. Some of them are performance, but it's not that simple either. Rust lifetimes are definitely about fast correctness, but it absolutely enforced "correctness" that you would not get with a global interpreter lock, because the principles of never having multiple mutable aliases simply makes sense given the machine model we have today.
So then TypeScript. Let's assume in aggregate it somehow prevents absolutely no bugs despite the obvious fact that it prevents entire classes of bugs that are common in idiomatic JS. Well, guess what? It still offers a ton. For example, it makes refactoring significantly easier. It's not even a discussion, refactoring old code is much easier when it's statically typed, even if it's ossified and weird and full of Chesterton fences. It's night and day. Typescript also offers excellent code intelligence: very accurate autocomplete, inline documentation, automated refactoring options, and yes, more static analysis options than just type checking; being able to statically analyze the code deeper opens up an explosion of linters and checkers for all sorts of things; checking for improper usage of React hooks, or common lodash mistakes.
> Hacking it into a scripting language is plain looking for trouble.
On the contrary, I wouldn't catch myself writing JS without TypeScript anymore. I consider the investment very small compared to the benefit.
In the real world, I often do not get the chance to start new projects from scratch, but instead wind up walking into existing messes. The last JS project I walked into wound up having thousands of errors per day that could've been prevented by static type checking, caused by hundreds of different bugs. And that's just what we could observe by adding metrics: there were still more bugs that were uncommon enough to not be caught initially. When you're dealing with an old ossified codebase like that, you sometimes wind up with more bugs going in than out a lot of the time. The only reliable way I've seen to reverse that trend is by incrementally adding more static analysis. Hope, after all, is not a strategy.
I don't believe there is an objective truth here, but I have strong doubts about the points presented here. The argument for static type checking is strong: it simply prevents classes of bugs, end of story. That's a very simple story and does not require any gymnastics to explain. The argument against static type checking feels very hand-wave-y at best. The fact that we keep landing on this weird point about how it is "primarily" used for performance especially, since I don't think that's true. I think you are mistaking the fact that dynamically typed languages are slow due to the inability of the compiler to optimize for statically typed languages choosing to be static simply for performance. I don't think it's even true for C.
3% is the right order of magnitude and if it is +10% more than that that wouldn't make any difference. Static typing would still be twice as bad as dynamic typing when it comes to code correctness.
"What if you already know the majority of your bugs, as logged today, could be prevented by a type checker?"
You would be a very bad programmer, since the vast majority of bugs are logic bugs.
"why does C do static typing" Code performance. It needs them to effective map types to registers avaliable on the machine it's been compiled for.
Rust lifetimes are about getting C like performance without the bugs introduced by using the techniques required for C like performance. You could remove Rust lifetimes and get all the same safety, it's just the programs would run slower due to garbage collection.
"So then TypeScript. Let's assume " TypeScript is an obvious bad example since JavaScript is a very bad language since it was hacked together by browser makers over several decades. You could make a dynamic typed equivalent of TypeScript and it would have the same advantages.
"The argument for static type checking is strong" It's incredibily weak it prevents a class of bugs that only occur very rarely in dynamically typed languages (3%). By both increasing your development time by 2.5x and increasing the total number of bugs in your program by 2.5x.
You wanting to believe in static typing doesn't stop it sucking in the context of scripting languages.
> You would be a very bad programmer, since the vast majority of bugs are logic bugs.
I don't work alone. Most of the time, I work on projects that predate my involvement, and are old enough to have accumulated cruft.
But I think I found the disconnect. This right here is the key:
> since the vast majority of bugs are logic bugs
You might think that there is no way a type checker could prevent a logic bug. You're wrong. It is clear to me now that when you say 3%, you are talking not about the type of bugs that static type checkers are capable of preventing, but only errors that are explicitly related to types. Because if you model your code with types as you go, types do prevent all kinds of logic errors. When you write code with strong typing, it can prevent impossible state machine transitions, ensure that you handle all cases of a set of possibilities, ensure that you follow API contract obligations, and more.
Exactly how much a given type system is capable of inferring and decoding varies. TypeScript is definitely the state of the art for type erasure systems built on script languages, and what it is capable of encoding is pretty impressive.
Maybe, maybe, the amount of bugs that you can attribute to typing issues is 3% if we're only regarding Python TypeErrors; but, a proper type checker goes far beyond that.
But if it can't catch 60% of all errors and it can't.
Then it's worse than dynamic typing.
This isn't complicated. If you are excluding performance, then static typing is inferior to dynamic typing. It's that simple. No ifs, no buts.
I do write statically typed code but that's for performance critical code. Since I've got good experience of both, I understand the differences very well.
I assure you that using static typing in a scripting language like Python is a mindnumbingly stupid thing to do.