Tuesday, January 17, 2012

Clojure records, types, and protocols

Clojure offers a way to structure data in the form of records, types, and protocols. Even more interesting, functions (behavior) can be added to these structures. If you are coming from an object-oriented background this probably sounds familiar, but there are differences that are both small and large worth noting.

Protocols, in clojure, are roughly equivalent to an interface in Java. A clojure protocol, like a java interface, defines a contract that an implementer agrees to when implementing a protocol. Simple enough right? Not so fast, what might strike someone as strange (and can be a potential pitfall) is that concrete implementations of a protocol are not required to implement all of the methods defined on the protocol. That means that when using a protocol there are not guarantees that a function in the contract of the protocol is implemented on the concrete record or type. So, when receiving or dealing with a protocol, as an abstract contract of available functions, the record or type behind the protocol might not be living up to its end of the contract. This is something to watch for when using protocols.

Records are a way to structure a persistent map. When defining a record the user can define all of the fields they wish to hold within the map. These fields become the keys and the values are populated during creation of an instance of a record. What is different from object-oriented programming is that the values of the fields never change after the record is instantiated, the data is immutable. When will a record be useful? When we want to define a set of fields that is commonly repeated and then provide a common way to populate the fields and refer to the map. Now that we understand the data side, how does the behavior side fit in? The only way to place functions within the record is to implement a protocol. Once a record makes use of a protocol it is then able to implement as many (or as few) of the protocol's abstract functions as it needs. Remember, however, that the data is immutable and the functions can not manipulate the stored data.

Types are very similar to plain old java objects (POJOs). Where a record is a map, a type encapsulates its data using the dot-notation, as one would use in most any object-oriented language. As with records, types must implement a protocol to have functions and is limited to the functions available on the protocol. Also, as with records, types do not need to implement all of the functions of a protocol.

After reading the high level overview it would probably be nice to look at some code:


No comments:

Post a Comment