1. 9

  2. 7

    This is a good idea that has been used with varying degrees of success (lots of Javascript examples, and of course Typed Racket and earlier experiments with typing scheme), but the problem is often that when a language is designed without types and then type checking is added later, the task is a lot harder. You end up with a much more complicated type system (untagged union types, for example, and context sensitive typing, where runtime code assertions should imply type refinement, like if you test that a value has a certain type, in the branch where it succeeds, it should now be checked as that type), which then makes it much harder (or impossible) to do type inference. That means that you are going to pay much more of a cost in terms of writing down types than you would have in a language that was designed with a static type system in mind.

    Also, if what you have is just a linter, ie it only reports things it can detect are errors, and doesn’t report when it can’t figure things out, it’s pretty easy to end up with programs that have plenty of annotations but don’t have enough for the linter to actually catch many errors. That’s somewhat unsubstantiated, so take it with a grain of salt, but when the linter is supposed to work when it can’t figure out all the types it necessarily admits the possibility that it will run without figuring out almost any of them. To some extent, the whole point of a type system is that it covers the whole program, as that’s really the only way you can start counting on it to catch certain types of errors (which, really, is the whole point - it eliminates them from the list of things that programmers have to worry about).

    Which isn’t to say doing this is a bad idea, just that the end result is probably going to be a much worse typed language than modern ones (F#, OCaml, Haskell, Rust, Scala…), and this isn’t really a best-of-both-worlds solution. And for places where performance isn’t critical (which, if you’re using Python or Ruby, it probably isn’t), it’s not clear to me that this is going to produce all that much better results than runtime type assertions (ie, contracts).