September 28th, 2013
(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: firstname.lastname@example.org
Why optional typing?
Dynamic languages have long been criticised for being hard to maintain at scale. When you grow to a large team or a large code base, it becomes more difficult to refactor a code base, to understand how it works, and to make sure it does what it should.
The standard solution is great testing, and obviously we at CircleCI are big fans of great automated testing. However, what we’re really about is productivity, and optional typing can make you much more productive, because you it can can provide guarantees that testing can’t. This is amazing for hard-to-test features, and to increase your coverage without spending a massive amount of time doing so.
Not your parents’ typing (unless your parents hacked in ML)
This isn’t typing as you expect from the Java world. Typed Clojure is much much more powerful than that. Most Clojure code, like other scripting languages, is about manipulating hashes and lists. Typed Clojure allows you type-check duck-typed languages.
Typed Clojure is based on important advancements in combining typed and untyped languages. Based on Typed Racket, it further proves that optional (or gradual) typing is practical to use in production code.
Technically, Typed Clojure is a different form of type-checking than Java and older languages. Those languages use nominal typing, where you type-check the names or classes of a value. Although that is still used in Typed Clojure, the major feature is about structural typing, where you can type-check the structure of an object or hash or list.
This allows you to have incredibly powerful type-checks, while staying lightweight and flexible. For example, you can guarantee that:
nil isn’t allowed
a hash must have a defined set of keys (each with their own types!)
a hash must have only known keys
a value must be one of a set of types
a vector has a known size
many other properties about set, lists, vectors, and object instances.
Not only that, but because it’s optional, adding type-checking can be done incrementally, providing only value where you need it. You can annotate a single library, a single namespace, or a small set of functions, and you can use libraries that aren’t typed.