Marshall Bowers

Conjurer of code. Devourer of art. Pursuer of æsthetics.

Static Typing Has Ruined Me

Saturday, July 23, 2022
480 words
3 minute read

There was a time in my life where I found static types burdensome.

The curricula for the programming classes in my senior year of high school and freshman year of college used Java as the language du jour. Java, being statically typed and (at the time) lacking in pretty much any semblance of type inference, required type annotations everywhere. There's only so many type annotations you can put in front of variables until the whole thing begins to feel like a massive drag.

This made JavaScript feel all the more like a breath of fresh air during my internship the following summer. Being able to write working code without having to denote any type information felt freeing. It certainly halped that my youthful hubris allowed me to sweep all the subsequent issues resulting from the lack of a static type system under the rug.

My honeymoon with dynamically-typed languages continued until my junior year of college when I was introduced to two new languages over the course of my "Programming Concepts and Paradigms" course. The first of these was Common Lisp: a fascinating language in its own right, but not the one that ultimately captured my heart.

That honor belongs to Standard ML (SML).

Our final assignment for the class was to write traversal functions for a binary tree. The solution looked like this:

datatype 'a BinaryTree = empty | tree of 'a * 'a BinaryTree * 'a BinaryTree;

fun preOrder (tree(root, empty, empty)) = [root]
| preOrder (tree(root, empty, right)) = root :: preOrder right
| preOrder (tree(root, left, empty)) = root :: preOrder left
| preOrder (tree(root, left, right)) = [root] @ preOrder left @ preOrder right;

fun inOrder (tree(root, empty, empty)) = [root]
| inOrder (tree(root, empty, right)) = root :: inOrder right
| inOrder (tree(root, left, empty)) = inOrder left @ [root]
| inOrder (tree(root, left, right)) = inOrder left @ [root] @ inOrder right;

fun postOrder (tree(root, empty, empty)) = [root]
| postOrder (tree(root, empty, right)) = postOrder right @ [root]
| postOrder (tree(root, left, empty)) = postOrder left @ [root]
| postOrder (tree(root, left, right)) = postOrder left @ postOrder right @ [root];

Something clicked in my brain while writing this program. The simplicity and elegance of the traversal functions showed me that code can be beautiful. Additionally, this entire program is statically and strongly typed, but there isn't a type annotation in sight!

Since that day I've been sure and wholly ruined by static types. I'm loathe to write code in a dynamically-typed language, and in the times I'm forced to the experience is frustrating and fraught with errors. When working in any moderately-sized codebase I ask myself how anyone could make sweeping changes or refactorings in the absence of a static type system.

It seems that the industry at large has also realized that static types are a Good ThingTM, which is good news for me as I'd be a significantly less effective engineer without them.