The non-broken promise of static typing

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!

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?

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.

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.

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.