It's quite interesting seeing the polarization of people's opinions on type systems. I have friends who adamantly argue that static types slow them down and prevent them from adapting quickly. On the flip side I have friends who claim they cannot write code without static types and that JavaScript is unusable.
When really, both styles have their value. Static types are very useful and do provide some nice safety. However, static types can also be quite annoying and force you to acquiesce to the type system. You have to learn to "speak" types, which can be very tricky. There's a joy that comes with the freedom of no static types.
> You have to learn to "speak" types, which can be very tricky. There's a joy that comes with the freedom of no static types.
If you struggle with "speaking types" then that's an indication that you don't understand the domain of values your code works with. Having a solid plan for exactly what shape your data can take is empowering, not restrictive. To some extent, certain restrictions provide greater freedoms in the sense that you can make more accurate assumptions about your data without needing to perform a bunch of run-time checks or write hundreds of unit tests to ensure your code works in all possible situations.
> If you struggle with "speaking types" then that's an indication that you don't understand the domain of values your code works with.
I'm not sure I agree. I've met intelligent programmers who can elucidate the domain of values which their code is utilizing, but simply cannot do so in the framework of a given type system. Or perhaps they just find it difficult or painful to conform their description to the grammar of the type system. Understanding the data domain and being able to describe it in a specific type system are different skills.
Even if one is completely in favor of static types, it's important to be sympathetic to this point of view so that we can design better, more friendly type systems going forward.
There are definitely some failings in static type systems that can cause programmers to struggle, regardless of how well they understand their domain of values.
I guess I was thinking more of people I've talked to who advocate for dynamic type systems for rapid prototyping, because they don't want to be bothered to stop and think about their types first — they kind of just go with an approximate view of their data held in their head. I think this style of programming leads to a lack of understanding of the domain of values down the road, which is more what I meant to address. But I did not sufficiently explain this in my previous comment haha.
> I guess I was thinking more of people I've talked to who advocate for dynamic type systems for rapid prototyping, because they don't want to be bothered to stop and think about their types first
Totally! I wish we taught more type directed programming in general. It's a good way of thinking and can guide your process very nicely.
I've slowly come to the conclusion that instead of assuming my friend who doesn't like static type systems is misguided, I should try to figure out what aspects of static type systems need improvement so that a person like him would use them. Even if I don't agree with him, I can still use his point of view as a different perspective.
> I've slowly come to the conclusion that instead of assuming my friend who doesn't like static type systems is misguided, I should try to figure out what aspects of static type systems need improvement so that a person like him would use them. Even if I don't agree with him, I can still use his point of view as a different perspective.
Ah yeah, that's a very pragmatic view on things! And totally reasonable. I intend to work on improving type systems, so this is definitely the mindset I strive to maintain more often than not haha.
Most often in imdustry, you have to begin any complex project without a deep understanding of your domain values, because that understanding only comes iteratively. In my experience, the biggest drawback of static typing is that it forces you to design your types when you still don't have enough knowledge, and changing it later is painful.
> In my experience, the biggest drawback of static typing is that it forces you to design your types when you still don't have enough knowledge, and changing it later is painful.
I 100% understand where you're coming from, but I view this as an advantage of static type systems. The "pain" is you having to go through your code and make sure that you change your usages of given types to match the new definitions, right? This is forcing you to make sure your code is still correct with respect to the types.
Most dynamically-typed languages let you skip this part, but this causes you to lose clarity. Is your old code still correct? Or is it just mostly correct? Are there new unexpected edge cases being introduced that you didn't bother to go check on due to faulty now-outdated assumptions?
Changing your types is a pain, I agree. But programs are just about data transformations, and types are representations of the shape of those data. Changing your types without changing every part of your program that touches those types inherently means that your program is now running on invalid assumptions. Sometimes it works fine, but I think it is better to know it's fine than to just say "Well, it seems to work in most cases."
The risk you describe is real, but good testing coverage lowers it in a way that I find way more efficient than static type checking. When I have that good coverage - which for me means the full pyramid of testing, not just unit tests - I almost never find that problem.
Refactoring when you change your understanding of the domain can be a lot of work also when you have dynamic typing and lots of tests, but if the tests are well designed, I rarely feel that as painful as it was when I felt I was battling with the type system.
PS: my main experience with static typing was with c++, it's possible that more modern type systems could have improved the situation.
I find static types useful for gaining that understanding. It's very helpful to clear up confusion in my head to start prototyping by writing down type definitions and functions' type signatures without implementations before starting to write the actual code. Of course, this only works with a language where the type system is sufficiently painless and allows for such experimentation without a ton of boilerplate (i.e. the language is not Java).
When I was using c++, the pain came when I discovered that I had to refactor my types because of some cases I didnt know about... Maybe that's easier with more modern statically typed languages.
Personally, I have a bad working memory and struggle to remember the structure of data. I constantly have to jump around and try to find the name of things / recall their hierarchy
With static typing I can just highlight a type / jump to the definition or get intellisense. I also find it useful when I have specific names for data types because I can reason about things / communicate them easier
To me taking the time to specify types or wrangle the type checker is worth the reduced mental burden of having to remember the shape of things, and refactor data structures confidently
That's basically my reasoning as well. I want the IDE to tell me things so I don't have to look up documentation all the time, especially since most of the time I'm working on code I had no part in originally. It's a helpful learning tool more than anything else.
Dynamically typed languages are perhaps not as easy to program in as thought. You need a lot of practice in naming things to produce readable code. For example, in Java it doesn't matter if the count of items is stored in a variable named 'n' or 'f'. The type would still be int. In Python, 'f' would be a confusing name, but 'n' would be acceptable.
Same problem with all dynamically-typed languages, really. It's too easy to write the wrong thing and not find out about it until you've written umpteen unit tests. This can happen due to typos, refactoring, or whatever else. Only JavaScript is worse because it's weakly typed too, so it performs implicit coercions in an effort to make your code always do something (meaning your unit tests have to be very good to really ensure your functions do what you think they do).
A static type system ensures that, at the very least, all the types line up at compile-time. You find type errors much faster than with a dynamically typed language, and this can guide a much less exhausting development cycle.
IMHO Javascript is "unusable" because you can mutate state (among other things). Rich Hickey has a few other arguments against static typing and OO such as names dominating semantics and "types are an anti-pattern for program maintenance and extensibility because they introduce coupling. They’re also parochial." I think he said that in his talk called "Effective Programs":
As much as I liked Clojure when I dabbled for a few months it didn't really fix my dislike for dynamic languages, but I imagine core.typed / spec would fix that for me if I gave it another shot
I loathed dynamic typing mostly because you had to jump around code to understand what the shape of anything was, and it distracted me from the problem I'm trying to solve
In ML influenced languages types actively help me plan a solution, and rarely get in my way
When really, both styles have their value. Static types are very useful and do provide some nice safety. However, static types can also be quite annoying and force you to acquiesce to the type system. You have to learn to "speak" types, which can be very tricky. There's a joy that comes with the freedom of no static types.