Originally posted on my blog
A while back I read an article about how static typing does not prevent
bugs being added to software. The article is appropriately named: The broken promise of static typing. The author conducted research by generating and comparing 'bug density' scores for GitHub repositories. The bug density score was determined by getting the average number of issues labelled 'bug' per repository.
The results showed that there were not any less bugs in statically typed languages vs dynamically typed languages. The author concludes on the results:
"the lack of evidence in the charts that more advanced type languages are going to save us from writing bugs is very disturbing."
While this article brings up good points and makes an effort at original research, I've always felt that the claims made were wrong. I strongly believe less bugs will occur when a statically typed language is used. However, I've never had any proper evidence to back up my claims...until now!
Enter: The Morning Paper, a blog that summarises tech white papers. It recently released an article talking about the same subject called: To type or not to type: quantifying detectable bugs in JavaScript.
The article covers a study of the same name. In it, researchers looked at 400 fixed bugs in JavaScript projects hosted on GitHub. For each bug, the researchers tried to see if adding type annotations (using TypeScript and Flow) would detect the bug. The results? A substantial 15% of bugs could be detected using type annotations. With this reduction in bugs, it's hard to deny the value of static typing.
While these results show a benefit from using static typing, people will continue to prefer a specific type system. So, let's hear from you! What type system do you prefer, and why?
Top comments (15)
This is such a fascinating topic. I have yet to go through the entire comment chain in @danlebrero 's original post which you linked, but I bet there are a lot of interesting points there.
There are a lot of great rebuttals there, for sure 😊
It's definitely an interesting and divisive topic. It's cool to see everyone's opinion on it
One trade-off I think about for static typing vs dynamic is the degree of testing. With dynamically typed languages, you are buying into testing in a big way to keep quality high. With statically typed languages, you are paying an up-front cost (type annotations) to let the compiler automatically test for a specific class of issues. I think the primary failure of static typing is that developers tend to assume (or hope) that type checking will catch more than it does. And tests are neglected which really should be written. But in dynamic languages, you are conditioned to write tests although some type-related issues might slip through.
My personal preference is static type checking in a functional language with type inference and an expressive type system. Type inference makes the language feel more dynamic since you don't have to annotate types in many cases. And an expressive type system can allow you to make types that cannot be used incorrectly. My choices which fit this bill are F# and Elm.
Agreed. I'd like to just add one thing:
Sometimes you hear people say "most error are not type errors". The thing is: yes they are. It's just that most people are not used to thinking of those errors as type errors.
Type systems can address all sorts of problems. From What To Know Before Debating Type Systems:
In LISP you can use macros and simple parses to check for certain types of code at compile time and you can check the callstack to make sure properties keep, sometimes it seems easier to grok that than complex type systems. I have to say that Haskell is pretty nice, but it sometimes you could build inflexible code. Like its hard to know before hand if you want a pure function or a functor or a maybed function and if you get it wrong you could end up rewriting huge amounts of your code although when run it will most likely work at the first time.
Yep, you make a good point regarding testing. While static typing will pick up problems, it's not going to save you from the infamous Null Pointer Exception!
Type inference with static types definitely feels like you get the best of both worlds. While not exactly in the functional realm, it's one of the reasons I've been looking at Kotlin for future projects.
That's another good thing about F# and Elm. Null is not an allowable value***. Instead you use Option/Maybe when a value may not exist. That also explicitly forces you to deal with the non-existent case. You can't forget, because it won't compile.
*** F# is on .NET. Most .NET libraries are imperative. Especially at the boundary of applications (deserialization, loading from DB) you still have to deal with nulls. But your core code can be free of them.
To me this isn't really about finding bugs. When the codebase start to grow and you need to find the impact of a change, there are IDE that will be able to find all the impacted code. Sure missing some impacts can be a bug. But just having the complete list is quite valuable. In some simple cases, the IDE will do the change everywhere like if I want to change a class or method name. If I miss some change, most often I'll find the bug early at compile time.
The sooner a problem is found, the lesser the cost.
But this is not only just that. The additional information provided in type provide context and documentation. They are used both by IDE to provide code completion and other nice features but also by developpers to understand what some object/type is able to do or not. This is quite valuable.
A big project with many people will benefit most from static typing as long as the toolling leverage the additional information and more than compensate for the added verbosity.
A small code base by one developper or very few that know by heart the code base what it does and what they want to achieve will be able to take shortcuts with a dynamically typed language and be more productive that way.
Note that Smalltalk had good tools and it was dynamically typed, in many types of applications you can write the application while the REPL is on to get lots of information on your project. A lot of IDEs even without using the type annotations used type inference as well, which worked very well with default arguments.
Yeah, I agree with all the points you bring up. Although, how often does a small, one person codebase dramatically increase to a large, multi-person project? ;)
I would say most successful projects in a company will eventually become something large. You'll want more features, the people working on it will change over time and so on.
Sure you can be in "one shot" mode where you create a website for client that will not change, maybe even for a short event and then you can trash it. But most often if it work well, if it is valuable you'll want to build on it and it will eventually become huge.
Most of the applications and libraries used by people around the world are actually big or huge. Your operating system, your beloved IDE, your photo sharing program, even just a network library...
But for one successfull application there hundred of failure. If you are alone and can go faster with a dynamic language and can fail faster, that's great. Once there a significant income/budget for the project as people recognize it's value you can always change technology. A bit like twitter that gone from ruby on rails to java and scala.
I have a problem with a study that focusses on only one programming language, and one that is particularly problematic because of its notoriously poor design (the infamous WTFs), and then draws a broad conclusion for all dynamically typed languages.
Robert Smallshire conducted what I believe is a fairer study that showed less than 2 percent of software defects may be attributed to dynamic typing. This is not a significant outcome and certainly not worth passing up on the many benefits of dynamic typing.
Last paper I read about static typing mentioned that only 15% of errors are caught by static type systems like Flow and TypeScript.
That seems really low for the extra work I put in.
I'd like to know if systems like Reason/OCaml are better with this.
The optional type system with Typescript is awesome. Slap Typescript on an existing JavaScript project and slowly add types as you need it, it's great!