|
As a Python user and fan I hear this complaint a lot. I understand but I can't really agree since things like typos and type fails pretty much never happen to me, at least in production. My secret? I use the REPL, heavily. (And not even in the grand Lisp fashion, because Python's REPL isn't very advanced, mostly I use it just off to the side and maybe or maybe not running an instance of the full program, or parts of it.) Using the REPL catches most of those things just as quickly as a compiler, plus it can catch things compilers don't, such as null pointer exceptions. Two lesser secrets are using a linter, which catches all sorts of issues too, and second actually getting the full program locally to a state where I can have it execute (most of) the new code I just wrote that I didn't verify in the REPL, or using data sources I didn't just define temporarily in the REPL, so I can make sure it seems to do what I intended. A lot of devs don't seem to do the second bit... Checked in code for Java compiles and passes existing tests and went through a basic code review but inevitably bugs get filed because it doesn't actually do everything the story said, it's like they didn't even try out their own code, it just looked correct and the compiler/tests agreed. I think when you're working with the REPL interactively instead of relying on the common "edit -> save -> compile -> ship it|start over" cycle you don't miss those details as much, because you're constantly trying out your own code. Maybe my experience is because I don't typically use dynamic languages as scripting languages, at least in the sense of quickly hacking up a script, saving, getting to skip the compile step (look how much faster it is to develop in dynamic languages!!!), and running it until it works. I have done that, but even then, I'm usually writing the bulk of the script in the REPL -- or rather in my editor that can send text to the REPL. It's quite different from what seems to be the thing that made these languages popular to begin with, which is not having to explicitly type everything and getting to skip a (potentially long) compile step (which also encourages more source sharing). |
The typos / type fail comments are shorthand for the real complaint, which is that a long-maintained large dynamic language codebase requires continuous vigilance. I've worked in dynamic languages for most of my career (Python, JS, Clojure) and typos/type-fails are pretty rare but if you haven't spent a half day tracking down a bug that turned out to be one of these at some point in your career, I'd be quite surprised. The breakdown comes when someone not familiar with the code makes a change without fully considering the consequences and it goes through something that nil-puns so the error isn't detected immediately.
My experience with people who are really against type systems is that they haven't run into a language with a good type system. I'm a fan of the gradually typed JS dialects (Flow more than Typescript) since you get the quick hacking at the beginning combined with compiler-enforced vigilance once you switch over to maintenance mode. Type-inferred languages are also nice, particularly fully type-inferred languages. I think F# [0] is both terse and accessible, for example.
[0] https://fsharpforfunandprofit.com/why-use-fsharp/