What are hybrid maps?

A heterogenous collection of birds.

A heterogenous collection of birds.

Clojure people sometimes talk about hybrid maps. What are they talking about?

A map, in general, is a data structure that associates keys with values. There are two common usage patterns for maps in Clojure:

  • As records. The map acts as a collection of fields with predefined keys. For example, a row in a relational database is a record. When you query the database, you know what columns the result will have. Typically in Clojure, you get a map or a collection of maps as a result of database query.
  • As indices. The map acts as a collection of objects indexed by something. For example, you could represent a database table as a Clojure map of rows indexed by the primary key of each row.

See LispCast for a more extensive discussion of these patterns.

A hybrid map is a map that acts as a record and as an index at the same time. This pattern is not common – usually it’s better to have the index map as a field in the record. One case where it works nicely is the Clojure map destructuring syntax:

(let [{var1 :key1 var2 :key2 :keys [key3] :as result}
      (some-function-call ...)]

Here :keys and :as work like record fields, but the bindings for var1 and var2 work like an index.

What about heterogenous maps?

A map is heterogenous if it can contain keys and/or values of multiple types. If a map is not heterogenous, it’s homogenous. Here are some examples:

{:a 1 :b 2}         ; homogenous
{:a 1 :b "hello"}   ; heterogenous values
{:a 1 "b" 2}        ; heterogenous keys
{:a 1 "b" "hello"}  ; heterogenous keys and values
{}                  ; could be either!

This concept is not discussed much in the Clojure community, because Clojure maps are heterogenous by default.1 An example of less-heterogenous map in Clojure is data.int-map, where the keys must be integers. The values can still be anything, though.

The concept of heterogenous maps, and of heterogenous collections in general, is more interesting in statically typed languages like Scala and Haskell. Expressing the type of a homogenous map is straightforward, but typing a heterogenous map is more complex. This is can be seen in how there are separate libraries for heterogenous collections, like the popular shapeless library for Scala.

What’s the relationship between hybrid maps and heterogenous maps? There’s no relationship, really. Like records, hybrid maps often are heterogenous, but there’s no reason for why you couldn’t use a homogenous map for a hybrid purpose.

  1. Unless you argue that Clojure is unityped, in which case all Clojure maps are homogenous.

Comments or questions? Tweet to me or send me an e-mail.