Polymorphism in Clojure

First lets define what is Polymorphism. Simply put, polymorphism is about having a single interface for different data types.

Different types of polymorthism

There are different types, some with different names.

  • Static binding Time
    This is related to method overloading
  • Dynamic binding

Related to method overriding

interface Animal {
void makeNoise ();
}

Dog implements Animal {
public void makeNoise() {
System.out.println("Woof!");
}
}
Cat implements Animal {
public void makeNoise() {
System.out.println("Meow!");
}
}
class Main {
public static void main(String args[]) {
Animal cat = new Cat();
Animal dog = new Dog();

cat.makeNoise();//output: "Meow!"

dog.makeNoise();//output:"Woof!"
}
}

The output changes because of the different Animal data type.

Clojure being a dynamic language, we will be focusing on dyanmic polymorphism

Problem

You want to build function that changes dependent on the argument given.

Possible Solutions

An already existing used of Polymorphism in Clojure is the cons method which will add an element to a given list/vector/set input and return the result.

We could use if-branching, cond or condp. But these aren’t really polymorphic.

Lets have a look below.

(defn greet [name]
(if (empty? name)
(str "hello annon, how are you?")
(str "hello " name ", how are you?")))

This could work but it’s not idiomatic. Clojure has a better way of handling this kind of scenario.

We have a few possible solutions in Clojure that we could use to perform our own polymorphism.

Multi-arity functions

Arity is simply the number of input arguments in the function.

(defn greet
([] (greet "anon"))
([name] (str "hello " name ", how are you?"))
([name & more] (str "hello "
(apply str
(interpose ", "
(cons name more)))
", how are we all?")))

The greet function overloads itself when no argument is passed in, but what we can also do is handle more than 2 arguments are passed in.

Multi-methods

Multi-methods is a great way to introduce polymorphism. It reminds me when you go to the theatre. The usher takes your ticket(the input) and then directs you where you should sit(output) depending on whether you’re in premium seating, front row etc.

Clojure achieves this behaviour by defining a dispatching function with dispatching values which then determine the appropriate method to call.

(defmulti dance-style(fn [input] (:style input)))
(defmethod dance-style (:hip-hop [a] (str (:name a) " loves to pop and lock."))
(defmethod dance-style :ballet [a] (str (:name a) " loves to gracely move."))
(defmethod dance-style :default [a] ( str "I don't know what " (:name a) ". Has he's own style"))

(dance-style {:style :hip-hop :name "Cedric" :age 20 :experience :mid-level})
(dance-style {:style :ballet :name "Jada" :age 4 :experience :junior})
(dance-style{:name "Chuck Norris"})

So now when we call

(defn get-dance-style [style]
(dance-style style))

=>"Cedric loves to pop and lock."

Another thing you can do is have multi-methods across namesapces. This can be a good way to separate the different dance styles(in this example)
So you can then place all the hip-hop related dancers in the same namespace, all the ballet in their own namespace.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s