Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Clojure for Java Developers

You're reading from  Clojure for Java Developers

Product type Book
Published in Feb 2016
Publisher
ISBN-13 9781785281501
Pages 156 pages
Edition 1st Edition
Languages

Chapter 5. Multimethods and Protocols

We now have a better understanding of how Clojure works; we understand how to perform simple operations with immutable data structures but we are missing some features that could make our lives much easier.

If you have been a Java programmer for a while, you are probably thinking about polymorphism and its particular flavor in Java.

Polymorphism is one of the concepts that enable us to reuse a code. It gives us the ability to interact with different objects with the same API.

Clojure has a powerful polymorphism paradigm that allows us to write simple code, create code that interacts with types that don't exist yet, and extend code in ways it wasn't devised for when a programmer wrote it.

To help us with polymorphism in Clojure, we have two important concepts that we will cover in this chapter:

  • Multimethods

  • Protocols

Each of them has its own use cases and things it is best at; we will look into them in the next section.

We will learn each of these different concepts...

Polymorphism in Java


Java uses polymorphism heavily, its collection API is based on it. Probably the best examples of polymorphism in Java are the following classes:

  • java.util.List

  • java.util.Map

  • java.util.Set

We know that depending on our use case we should use a particular implementation of these data structures.

If we prefer to use an ordered Set, we might use a TreeSet.

If we need a Map in a concurrent environment, we will use a java.util.concurrent.ConcurrentHashMap.

The beautiful thing is that you can write your code using the java.util.Map and java.util.Set interfaces and if you need to change to another type of Set or Map, because the conditions have changed or someone has created a better version of the collection for you, you don't need to change any code!

Lets look at a very simple example of polymorphism in Java.

Imagine that you have a Shapes hierarchy; it might look similar to the following code:

package shapes;

public interface Shape {
  public double getArea();
}

public class...

Multimethods in Clojure


Multimethods are similar to interfaces, they allow you to write a common contract and then a family of functions can fulfill that interface with a specific implementation.

They are extremely flexible, as you will see they grant you a very fine control over what function is going to get invoked for a specific data object.

Multimethods consist of three parts:

  • A function (or method) declaration

  • A dispatch function

  • Each possible implementation of the function

One of the most interesting features of multimethods is that you can implement new functions for already existing types without having to write wrappers around your currently existing object.

The multimethod declaration works the same way as the interface; you define a common contract for the polymorphic function, as shown:

(defmulti name docstring? attr-map? dispatch-fn& options)

The defmulti macro defines the contract for your multimethod, it consists of:

  • The multimethod's name

  • An optional doctstring (this is the documentation...

Protocols in Clojure


Multimethods are just one of the options for polymorphism you have in Clojure, there are other ways to implement polymorphic functions.

Protocols are a little easier to understand and they might feel more similar to Java interfaces.

Lets try to define our shape program using protocols:

(defprotocol Shape
  "This is a protocol for shapes"
  (perimeter [this] "Calculates the perimeter of this shape")
  (area [this] "Calculates the area of this shape"))

Here, we have defined a protocol and it is called shaped and everything that implements this protocol must implement the following two functions: perimeter and area.

There are a number of ways to implement a protocol; one interesting feature is that you can even extend Java classes to implement a protocol without an access to the Java source and without having to recompile anything.

Let's start by creating a record that implements the type.

Records in Clojure

Records work exactly like maps, but they are much faster if you stick...

Summary


Now we understand Clojure's way a little bit better and we have a better grasp of what to look for when we need polymorphism. We understand that when needing a polymorphic function we have several options:

  • We can implement multimethods if we need a highly customized dispatching mechanism

  • We can implement multimethods if we need to define a complex inheritance structure

  • We can implement a protocol and define a custom type that implements that protocol

  • We can define a protocol and extend existing Java or Clojure types with our custom functions for each type

Polymorphism in Clojure is very powerful. It allows you to extend the functionality of Clojure or Java types that already exist; it feels like adding methods to an interface. The best thing about it is that you don't need to redefine or recompile anything.

In the next chapter, we will talk about concurrency—one of the key features of Clojure. We will learn about the idea of what the identity and values are and how those key concepts make...

lock icon The rest of the chapter is locked
You have been reading a chapter from
Clojure for Java Developers
Published in: Feb 2016 Publisher: ISBN-13: 9781785281501
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}