> I did like the discussion of dynamic vs. static though. It really feels dynamic is good for early codebases and static for late. So why aren't there languages that allow you to move to static as your codebase matures? TypeScript adds optional typing but doesn't quite go the whole way unfortunately.
I think that's a good idea. Maybe have a dynamically typed language, with other features that make dynamic languages good for using in a REPL and with more of a investigative programming style. And then have (another) language which is more static and have simpler runtime semantics, so that the language is easier to reason about but has less features that make it interactive. You might not even need the interactive features at a certain point, anyway, but it might be a problem if you want to move back to the more dynamic part in order to experiment with stuff. But that could perhaps be solved by making it possible to use the static language as the dynamic one, but not vice versa: for example if the difference is only in that the static one has type declarations and the dynamic one does not, simply ignore the type declarations and run it as the dynamic language, or defer it to be checked at runtime [0].
Someone in another thread brought up Typed Racket, which IIRC is implemented in Racket itself with macros.
http://docs.racket-lang.org/ts-guide/
[0] in GHC Haskell you can use a flag to defer type errors to be checked at runtime:
https://ghc.haskell.org/trac/ghc/wiki/DeferErrorsToRuntime