It is also worth pointing out first there are various flavors. There is a range of type strengths. Maybe from something like Haskell down to, I don't know, Javascript with stuff like [1,10,4,21].sort() = [1,10,21,4].
There is strong typing vs weak typing as well, and either can appear in a dynamic language. There also allowing nulls and also having or not having algebraic types.
> That's part of a more general preference, for preserving information. When I'm programming, I know what kind of thing I expect in a parameter, and I know what I expect to return.
Doesn't a functional single assignment language like Clojure or Erlang then make most sense? If your goal is to preserve information and knowing that no funny business has been happening behind your back (when you are not "figuratively" looking) isn't that what you want? This is even more important if this is a concurrent program.
You also have to ask yourself, what is the overall goal here. Ok maybe it is just aesthetics, maybe there is a small or (not so small) amount pleasure derived in figuring out the types and specifying that. Maybe it helps larger teams work better. Or it helps the compiler to make faster code (v8 might disagree though).
Most people would perhaps arrive at -- "I want my program to not crash as often". One way to do it is to then have a provable correct program. For avionics there is some degree of that. But it is very expensive. But another way is to assume your program will crash, no matter how strong your types are. Then fault isolation is a better strategy.
There's also two different (popular) typing approaches: inheritance and structural typing. Each gives you different ways of reasoning about functions and data.
Most of the hangups with static typing seem to come from three problems: Excessive boilerplate, excessive "type purity", and excessive compilation time. I would also argue that a lot of the hangups with static typing come from Java.
Java requires a lot of boilerplate to manage class constructors, etc. However, this is greatly reduced in new languages thanks to type inference.
Java is supposed to be about "pure" OOP, making it very difficult (and slow) to invoke any sort of dynamic method. It can't even type arbitrary methods, once again due to its object-centric focus. However, newer languages are offering more ways of dealing with different type systems, and/or dodging typing altogether in certain cases.
The last problem is with compilation time, which can eat into development time the same way that testing does.
There's newer static-typed languages that are making big improvements across all of these problems. Scala, Haxe, Dart, and Typescript are ways of making development easier for pre-existing platforms... either by relaxing type issues on the jvm, or providing type features for dynamic runtimes (js).
On the other hand, dynamic languages are starting to get very sophisticated linters that are catching classes of errors that are typically found by static typing.
So, in a way, both camps are addressing problems in their own way. I'm primarily in the static camp, but I develop using a lot of dynamic languages, and have been impressed with the tooling and resources available there. However, I see more improvements coming from the new static languages.
My sweet spot these days is Kotlin, which checks on all three points (I use both Scala and Kotlin in IDEA and it's not even close in compilation times).
There is strong typing vs weak typing as well, and either can appear in a dynamic language. There also allowing nulls and also having or not having algebraic types.
> That's part of a more general preference, for preserving information. When I'm programming, I know what kind of thing I expect in a parameter, and I know what I expect to return.
Doesn't a functional single assignment language like Clojure or Erlang then make most sense? If your goal is to preserve information and knowing that no funny business has been happening behind your back (when you are not "figuratively" looking) isn't that what you want? This is even more important if this is a concurrent program.
You also have to ask yourself, what is the overall goal here. Ok maybe it is just aesthetics, maybe there is a small or (not so small) amount pleasure derived in figuring out the types and specifying that. Maybe it helps larger teams work better. Or it helps the compiler to make faster code (v8 might disagree though).
Most people would perhaps arrive at -- "I want my program to not crash as often". One way to do it is to then have a provable correct program. For avionics there is some degree of that. But it is very expensive. But another way is to assume your program will crash, no matter how strong your types are. Then fault isolation is a better strategy.