Of Pseudotypes

Pseudotypes are a structure which have been on my mind a lot recently, mainly due to reflecting on the code which I have written over the last eight months as I've been mastering Clojure. It seems that a common design pattern in Clojure, and one which the community supports is to create what I've referred to more times than I can count on IRC as "structured maps", maps with keys defined by the programmer, and then manipulate these maps as if they were objects in the same manner as Python and other dynamic languages which provide a "maps as objects" structure.

This leads to the construct which TimMc and I were discussing as "pseudotypes", programmer structured maps which behave for all intents and purposes as objects yet which lack all benefits of a type system. I take some offense at this, as it can lead to confusion of data models. Several of the bugs which I've hacked out of this blog in the last few weeks were arguably due to this concept. Due to the lack of behavior guarantees provided by runtime maps it is impossible for any static system to indicate that can

Several of the bugs in my traffic system for instance were due to the 3AM typing mistake of saying _is instead of _id. Aside from the fact that I shouldn't be using _id directly, I had no warning of this error until I re-read the code and discovered my typo three months later during a major refactor.

That and for the most part map-based objects aren't very performant. We're all told in CS 101 (or equivalent) that hashtable insertion and lookup is O(1), but so is struct access! Which is more efficient: pointer arithmetic into a known layout structure or computing some hash function of a Key object and then using that to do a lookup by indexing of some object that could be spread all over physical memory? Yes that was rhetorical, 10 for 10 the struct lookup is faster.

For this reason the LuaJIT actually does a lot of really crazy stuff to avoid making objects for as long as possible by keeping values in registers or on the stack. Only when the "object" leaves scope does the LuaJIT actually construct the map as the programmer thinks it exists. This is a really cool trick, but to the best of my knowledge Java only really does function in-lining and dead code analysis not this sort of data hacking.

Anyway that's besides the point, and far below the level I intended for this piece. My main complaint with pseudo-types is that well you get no type warnings at all until a runtime type error occurs and it is far too late.

"Besides that, how was the play Mrs. Lincoln?"

Pseudo-objects are considered idiomatic in Clojure and are here to stay. The real question is how can they be improved to provide even a little feedback to support programmers decisions while they're writing.

I already have a partial solution to the problem in the form of pseudotypes a library I wrote after talking to TimMc which at least allows for the creation of type semantics for pseudotypes and pseudo-objects. However as with equivalent tools for Python, all that is really going on here is that I layer on extra runtime protection. Static protection is what I want, so static is next on the feature list.