It's true, it has some really bad parts but you can avoid them.
If I could design the perfect language for myself, it would have the syntax of JavaScript and the portability of JavaScript but it would use Python's strong duck typing approach.
It's true, it has some really bad parts but you can avoid them.
If I could design the perfect language for myself, it would have the syntax of JavaScript and the portability of JavaScript but it would use Python's strong duck typing approach.
It gets really old to get something like "NoneType does not have blah" in a deeply nested, complicated data structure in python, but obviously only at runtime and only in that hard to hit corner case, when all you did is forget to wrap something in the right number of square brackets in some other part of the code.
I haven't fully given up on python, but I only deal with it using mypy, which adds static typing, anymore.
My hope is one of the Next Big Things in programming languages is the widespread adoption of incremental typing systems.
So during the early stages of dev you get the productivity benefits of dynamic and loose/duck typing as much as you want, and then as the code matures - as the design firms up - you begin layering in the type information on different parts of the program (and hopefully the toolset gives you a jump start by suggesting a lot of this type info for you, or maybe you specify it only in places where the type info can't be deduced).
Then those parts of the program (and hopefully eventually the entire program) are strongly and statically typed, and you get all of the associated goodies.
For instance, take function definitions. By just adding types to the function's arguments, you're potentially saving the reader a ton of time and mental overhead since they don't have to chase down the right the chain of function calls to figure out what it is exactly (or is supposed to be) that's getting passed in.
My focus is message-passing, as opposed to instance-passing. Passing around instances can lead to 'spooky action at a distance' if multiple parts of the code hold on to a reference of the same instance, so I avoid it as much as possible.
The main advantage of static typing is that it helps you to safely pass around complex instances, which I happen to avoid doing anyway. So while I don't see static typing as inherently harmful, it offers me diminishing returns as my coding style improves.
In JavaScript land though, TypeScript forces me to add a transpilation step which forces bundling of my code and adds complexity which causes a range of really annoying problems in various situations. As people like DHH (founder of Ruby on Rails) have shown, we have the opportunity to move away from bundling and it yields a lot of benefits... but it's not possible to do with TypeScript in its current form.
It's particularly difficult for me because I actually like the syntax of TypeScript and its concept of interfaces. Interfaces can be consistent with the idea of passing simple objects which serve as structured messages between functions/components; rather than live instances instantiated from a class. I can treat the object as named parameters and not hold on it.