This week I came across a fantastic article by Eric Normand on the whole "static vs dynamic" debate, written by someone with the unique perspective of having worked professionally in both Clojure and Haskell.
The article is worth a read, but I want to focus one one line in particular that stuck with me. I don't fully understand it, and am hoping DEV may be able to shed some extra light.
The author was quoting a Rich Hickey talk. For the uninitiated, Rich Hickey is the creator of Clojure, a dynamic functional Lisp dialect for the JVM, and current CTO of Cognitect. Part of his cult of personality has stemmed from the rather excellent and rather opinionated talks he's given discussing both Clojure specifically and his personal take on the current state of the software ecosystem and how it applies to the sorts of problems he solves. (The rest stems from his phenomenal hairdo.)
That's a huge takeaway, something Normand takes extra care to identify: Rich Hickey isn't talking about the merits of static vs. dynamic typing in the general case. He's concerned with how it applies to his problem space. This is a detail that is all too often lost when these debates flare up, but is a factor when making absolutely any technical decision at all, and is important to keep in mind when engaging in this sort of discourse.
The line in particular that caught my eye was when he's discussing the use of
Maybe in languages like Haskell to handle the concept of optional values. Instead of a
String, you'd type your field
Maybe String. Now if can either contain a string or not and still be properly typed. You used pattern matching and destructuring to get at that actual value when your code needs to do something with it. You use it when you don't know for sure whether or not this value will exist at all times in a given record.
Rich Hickey doesn't like this. He disagrees with this approach, stating "you either have it or you don’t". It makes sense, too. For the sorts of programs Clojure is designed to address, everything would be wrapped in a
Maybe. These are long-running systems with high fault tolerance and constantly changing business needs. These systems do not lend themselves to hyper-rigid beautiful strongly-typed structures. If the spec changes, you don't want to have to make structural updates across every file in your project. You want to be able to just deal with objects of different shapes.
I can understand why it may be cumbersome to explicitly include a
Maybe on every single value, but I'm less clear on why it actually represents an inaccurate model of your system. In fact, not knowing Kotlin it actually kinds seems like that's what they're approaching - reducing the overhead for a nullable type to a single character.
That sounds like it works to me, but it also feels like there's truth to Hickey's perspective. When your system is running and you have a record, he's right. You don't "optionally" have a string here at runtime. You've either got it or you don't. That's just true. It seems like the
Maybe-based model is indeed a workaround for the convenience of the programmer, as opposed to an accurate model of a real-world phenomenon. At the same time, though, it does seem to model the expected behavior, and at runtime you'll still need to dispatch logic based on whether or not a given field is present.
Do you agree? Disagree? I've always felt
Maybe to be an effective solution to this problem, and this read has made me want to step back, consider the issue more carefully, and collect some perspectives.
Photo by marc liu on Unsplash