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:
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.
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
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.
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.
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.
Optional type systems are the future. I especially like how typescript does it. That type system is a thing of beauty.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.