What qualifies a programming language as dynamic?

I don’t think there is black and white here – there is a whole spectrum between dynamic and static.

Let’s take two extreme examples for each side of the spectrum, and see where that takes us.

Haskell is an extreme in the static direction.

  • It has a powerful type system that is checked at compile time: If your program compiles it is free from common and not so common errors.
  • The compiled form is very different from the haskell program (it is a binary). Consequently runtime reflection and modification is hard, unless you have foreseen it. In comparison to interpreting the original, the result is potentially more efficient, as the compiler is free to do funky optimizations.

So for static languages I usually think: fairly lengthy compile-time analysis needed, type system will prevent me from making silly mistakes but also from doing some things that are actually valid, and if I want to do any manipulation of a program at runtime, it’s going to be somewhat of a pain because the runtime representation of a program (i.e. its compiled form) is different from the actual language itself. Also it could be a pain to modify things later on if I have not foreseen it.

Clojure is an extreme in the dynamic direction.

  • It too has a type system, but at compile time there is no type checking. Many common errors can only be discovered by running the program.
  • Clojure programs are essentially just Clojure lists (the data structure) and can be manipulated as such. So when doing runtime reflection, you are actually processing a Clojure program more or less as you would type it – the runtime form is very close to the programming language itself. So you can basically do the same things at runtime as you could at “type time”. Consequently, runtime performance may suffer because the compiler can’t do many up-front optimizations.

For dynamic languages I usually think: short compilation step (basically just reading syntax), so fast and incremental development, practically no limits to what it will allow me to do, but won’t prevent me from silly mistakes.

As other posts have indicated, other languages try to take more of a middle ground – e.g. static languages like F# and C# offer reflection capabilities through a separate API, and of course can offer incremental development by using clever tools like F#’s REPL. Dynamic languages sometimes offer optional typing (like Racket, Strongtalk), and generally, it seems, have more advanced testing frameworks to offset the lack of any sanity checking at compile time. Also type hints, while not checked at compile time, are useful hints to generate more efficient code (e.g. Clojure).

If you are looking to find the right tool for a given problem, then this is certainly one of the dimensions you can look at – but by itself is not likely to force a decision either way. Have a think about the other properties of the languages you are considering – is it a functional or OO or logic or … language? Does it have a good framework for the things I need? Do I need stability and binary backwards compatibility, or can I live with some churn in the compiler? Do I need extensive tooling?Etc.

Leave a Comment