The preface is that dynamically typed programs and languages are inherently fallible by nature, especially in a large codebase, as it makes it nearly impossible to create a "proof of correctness". Dynamic typing creates failures that can only be seen upon execution of the code, not compilation, allowing errors to pass through that might not be caught during testing.
Since scripting languages have no compilation phase, they rely entirely on tests
and linting to enforce proper use and prevent errors, but loose typing makes
this inherently difficult to do. In a language where
2 == "2", concepts such
as referential transparency are impossible to attain. In C, this is equivalent
to every function returning a
void* with no static method of enforcing its
type or that it even exists.
Why This is Okay
With proper documentation and source control, code reviews and test driven development can catch the issues that would be caused by dynamic typing before they reach production. And in the event that they do, then - in a properly documented and organized codebase - the functionality can be changed and fixed quickly without causing any problems or requiring a rewrite of the entire codebase which one might experience in a language that is statically typed.
Dynamic typing doesn't just bring languages a lack of stability; it allows for useful functionality as well, which might not otherwise be possible:
The absence of a required compilation stage means that tests can be run as soon as your code is written, or even while you're writing it.
The lack of verbosity brought by dynamic typing means that common functionality can be written quickly and without context. For example: truthy values can be used to quickly determine whether something exists, regardless of what it is. The integer
0is false, and so is an empty string. However, even though
0 == '0', the string
'0'is a truthy value and will evaluate to true.
"Destructuring assignment" is also a cool example of the advantages that prototype-based data and a lack of verbosity can bring:
let [a, b, c = 4, ...d] = [1,2, ,4,5]; // a = 1, b = 2, c = 4, d = [4, 5]
times, but there is a clear option to just not use them. In most cases, loose
2 == 2) can be replaced by strict comparisons (
2 === 2) that
only evaluate if the operands are of the same type.