| The way I see it: Your type system is sound or complete (cannot be both, if it's a Turing-complete language). If it's dynamically typed, then it's probably complete but not sound (many, but not all, dynamically typed language implementations have some basic static type checking). If it's statically typed, it can be either sound or complete. The difference between sound and complete is: Sound type systems will reject valid programs that they cannot prove are valid; Complete type systems will reject only those invalid programs they can prove are invalid. In practice, the choice is more one of default these days: Do you default to static typing and allow some dynamic (runtime) type checking? C++, C#, Java, etc. Do you default to dynamic typing and allow some static (compile-ish time) type checking? Python, JS, Common Lisp, etc. This lets both sides have what they really want. They want to be able to express all valid programs (a complete type system) but they want to reject all invalid programs (a sound type system). They can't have it. So you end up choosing a direction to approach it from. Either start conservatively and relax constraints, or start liberally and add constraints. If you accept that, then the case for dynamic typing is that it's a choice to move from the too permissive extreme towards a stricter position. For me this works better (in general, though I also happily use statically typed languages like Ada) because I find it easier to add constraints to a relaxed system than to remove constraints from a restrictive system. |