Object Commando languages, development and design

26Mar/103

Clojure Protocols Part 1

Stale code warning

There have been small changes to the protocols code in Clojure. The below post is still useful, but a few details of the example code is different. See part 3 for the updated syntax.

Clojure Protocols

Protocols are a new feature in Clojure, set to be released in the next version. They provide polymorphism in a very Clojure-ish way. I think it's a great lightweight polymorphism implementation that has a lot of potential. In true Clojure style I think it meets the polymorphism objective and yet doesn't need to totally change the way you already write your code in Clojure. I'm breaking this entry into more than one piece to show some different ways that Clojure protocols can be used. Because it's so new, there are not a lot of docs out there on it, but Rich does some good documentation on the macros themselves. If you want to try these examples, make sure you're running off of the 1.2 version of Clojure (from Clojars or a local build from the Clojure git repo). First I'll start by defining a simple protocol:

(defprotocol TextOutput
	  (output-string [x string]))

In Java terms, I'm defining a TextOutput interface (actually a Java interface is being created, but more on that later), that has a single function named output-string that includes no implementation details. The input to this function is a little tricky though. I specified a parameter x and another one called string. The first parameter will be used to pass the implementation of the interface into the function. You don't need to write code to handle the parameter x and when you write your implementation, you'll act like it doesn't exist. A wiki type text output of an italics string would look like:

(deftype ItalicsOutput [] TextOutput
	       (output-string [string] (str "_" string "_")))

I have begun thinking about this in Java terms as a class ItalicsOutput that implements the TextOutput interface. Here in the output-string function, I only specify one parameter (not two). Next you can use this implementation with the following code:

(output-string (ItalicsOutput) "stuff")
"_stuff_"

I'm telling Clojure I want it to execute the output-string function, on the implementation (ItalicsOutput) (more in this below) with the argument "stuff". I think that below is a little more readable:

(def italics-impl (ItalicsOutput))
(output-string italics-impl "stuff")
"_stuff_"

Which just assigns the instantiated implementation to a variable which can then be used. These implementations can also have parameters, like:

(deftype PrefixedOutput [prefix-string] TextOutput
	       (output-string [string] (str prefix-string " " string)))

I think passing a variable in makes the instantiation step make a little more sense:

(def prefix-with-more (PrefixedOutput "more"))
(output-string prefix-with-more "stuff")
"more stuff"

Both implementations can be used together as well:

(defn print-all []
	(let [italics-impl (ItalicsOutput)
	     prefix-with-more (PrefixedOutput "more")]
	     (println (output-string italics-impl "stuff"))
	     (println (output-string prefix-with-more "stuff"))))

With output that would look like:

(print-all)
_stuff_
more stuff
4Mar/092

Type Inference vs. Duck Typing

I've been working with JavaFX 1.0 lately, which has a new language called JavaFX Script. The language is based on Java, but is intended to make it easier and more concise to write Swing GUIs. The language has some interesting features and the first one I noticed was Type Inference. Having done some work in OCaml, I was pretty excited to see this. One point of confusion that I think a lot of people have is the difference between duck typing and type inference. It is not necessary to explicitly define the type in either of these type systems, so they look very similar on the surface. Dig a little deeper, and they are actually quite different.

Duck Typing

Duck Typing is a dynamic language concept that boils down to this: if an object responds to a message, that's all we need to know. Put another way, we may know that the object we're dealing with is an Employee, and we know Employee has a calculatePay() method, but at runtime, the fact that the object is an Employee doesn't matter, all that matters is that the object happens to have a calculatePay() method. Later, when we add a Consultant class, that has a calculatePay() method, we can treat it as if it were an Employee (in this particular case). The key point here is that it is dynamic. Only at run time does this stuff happen.

Type Inference

Type inference is when the compiler determines what type an object is based on the operations that are performed on it. The key part to this is the compiler makes this check, it is not at runtime. As an example, if we had the simple code:

private String example = "text";

Is the String declaration above really necessary? It's quite obvious that example is a String, since it is assigned the value right there. Now if we tried to treat the example as an Integer, it would fail. It would fail not because it doesn't have the right method, but because it's not the right type. Another example is below:

public int add(int x, int y)
  return x + y;
}

Here we have defined x and y as integers. With type inference, we would specify x and y and the compiler would know that since + was used on it, it must be a Number. With JavaFX, trying to pass a String into a type infered method that expects a string will result in a compile time error (and if using Netbeans, a nice set of red marks).