MANNING
Amit Rathore
IN ACTION
Elegant applications on the JVM
www.it-ebooks.info
Clojure in Action
www.it-ebooks.info
www.it-ebooks.info
Clojure in Action
AMIT RATHORE
MANNING
S
HELTER
I
SLAND
www.it-ebooks.info
To my parents, my son, and my wonderful wife
For online information and ordering of this and other Manning books, please visit
www.manning.com. The publisher offers discounts on this book when ordered in quantity.
For more information, please contact
Special Sales Department
Manning Publications Co.
20 Baldwin Road
PO Box 261
Shelter Island, NY 11964
Email: [email protected]
©2012 by Manning Publications Co. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in
any form or by means electronic, mechanical, photocopying, or otherwise, without prior written
permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products are
A whirlwind tour 30
3
■
Building blocks of Clojure 60
4
■
Polymorphism with multimethods 90
5
■
Clojure and Java interop 106
6
■
State and the concurrent world 122
7
■
Evolving Clojure through macros 148
P
ART
2 G
ETTING
REAL
167
8
■
Test-driven development and more 169
9
■
Data storage with Clojure 189
10
1
1
Introduction to Clojure 3
1.1 What is Clojure? 4
Clojure—the reincarnation of Lisp 4
■
How we got here 5
How this book teaches Clojure 5
1.2 Understanding Clojure syntax 6
XML and parentheses 7
■
Lists, vectors, and hashes 9
1.3 The sources of Clojure’s power 10
Clojure and Lisp 10
■
Clojure and functional programming 11
Clojure and the JVM 11
■
Clojure as a Lisp 11
More advantages of Clojure 18
■
Clojure as a
functional language 18
■
Clojure as a JVM-based language 23
1.4 Clojure—beyond object orientation 26
1.5 Summary 28
www.it-ebooks.info
CONTENTS
viii
Keywords and symbols 53
■
Sequences 53
2.5 Summary 58
3
Building blocks of Clojure 60
3.1 Functions 61
Defining functions 61
■
Calling functions 67
Higher-order functions 67
■
Anonymous functions 70
Keywords and symbols 71
3.2 Scope 73
Vars and binding 74
■
The let form revisited 78
Lexical closures 79
3.3 Namespaces 80
ns 80
■
Working with namespaces 83
3.4 Destructuring 83
Vector bindings 84
■
Map bindings 86
3.5 Metadata 88
3.6 Summary 89
4
and accessing methods and fields 108
■
memfn 112
bean 113
■
Arrays 113
■
Implementing interfaces and
extending classes 114
5.2 Compiling Clojure code to Java byte code 115
Example–a tale of two calculators 115
■
Creating Java classes
and interfaces using gen-class and gen-interface 117
5.3 Calling Clojure from Java 120
5.4 Summary 121
6
State and the concurrent world 122
6.1 The problem with state 123
Common problems with shared state 123
The traditional solution 124
6.2 Identities and values 125
Immutable values 126
■
Objects and time 127
Immutability and concurrency 128
6.3 The Clojure way 129
Requirements for immutability 130
■
Managed references 131
Recap—why macros? 157
7.2 Macros from within Clojure 159
comment 159
■
declare 159
■
defonce 160
and 160
■
time 160
7.3 Writing your own macros 161
infix 161
■
randomly 162
■
defwebmethod 163
assert-true 164
7.4 Summary 165
P
ART
2 G
ETTING
REAL
167
8
Test-driven development and more 169
8.1 Getting started with TDD 170
Example: dates and string 170
8.2 Mocking and stubbing things 178
■
Accessing Redis from
Clojure programs 210
■
A Redis data mapper 212
9.4 Summary 219
10
Clojure and the web 221
10.1 An HTTP interface from scratch 222
The HTTP engine 222
10.2 Ring 229
Understanding Ring 229
■
Middleware 230
10.3 Compojure 232
Using Compojure 232
■
Under the hood 233
10.4 Generating HTML 236
clj-html 236
■
Under the hood 238
10.5 Summary 239
11
Scaling through messaging 240
11.1 Messaging systems 241
JMS, STOMP, AMQP 241
ActiveMQ, RabbitMQ, ZeroMQ 241
11.2 Clojure and RabbitMQ 242
AMQP basics 243
■
Maintaining status 290
Dispatching a job 292
■
Defining the slave 293
www.it-ebooks.info
CONTENTS
xii
Using the master-slave framework 295
■
Running a job 296
Seeing task errors 298
■
Rerunning the job 300
12.3 Summary 306
13
More on functional programming 307
13.1 Using higher-order functions 308
Collecting results of functions 308
■
Reducing lists
of things 310
■
Filtering lists of things 311
13.2 Partial application and currying 312
Adapting functions 312
■
Defining functions 315
Currying 316
13.3 Closures 321
and reify 360
14.4 Summary 366
15
More macros and DSLs 367
15.1 Macros 368
Anaphoric macros 369
■
The anaphoric if 369
The thread-it macro 371
■
Shifting computation
to compile time 374
■
Macro-generating macros 379
15.2 Domain-specific languages 383
DSL-driven design 383
■
User classification 385
15.3 Summary 395
index 397
www.it-ebooks.info
xiii
preface
I can tell you how much I enjoy being a geek. I can tell you how fascinated I was with
the punch-cards my dad showed me back in 1985. I can tell you how I got my first com-
puter when I was seven. And I can tell you that I’ve loved programming since 1989. I can
tell you a great many things about all that, but I’m not sure how interesting they’d be.
Instead, let me tell you about my quest for an answer of sorts. There’s been one
issue about our industry that has continued to puzzle me over the years: why is it that
no software project is ever as simple as it seems? Why is it that no project ever comes
what I could create with it. I started exploring dynamic languages and they felt more
expressive and malleable. Mostly, I enjoyed using Python and Ruby, and wrote several
nontrivial applications with them. I was working at a company called ThoughtWorks at
the time, and I had a lot of like-minded colleagues to work with. Eventually, one of
them turned me onto Common Lisp. The more I read about the language, the more I
began to realize how primitive other languages were. I used Common Lisp on a few
personal projects, but never did anything major with it; it did however have a pro-
found effect on my code in all the other languages I was using, and I kept looking for
an opportunity to use a Lisp on a real-world project.
I finally got my chance in 2008. I had moved to the Bay Area in California, and
ended up joining the founding team of a startup named Runa. In true Silicon Valley
tradition, our first office was in the founder’s garage. We wanted to disrupt the world of
eCommerce with Runa. The idea was to collect lots of data, use machine-learning tech-
niques to make sense of it all, and then present personal deals to select shoppers in real-
time. And in order to do all that, we had to overcome serious technological challenges.
The system needed to handle thousands of requests a second. It needed to handle sev-
eral terabytes of data a day. It needed to be scriptable via a set of high-level, declarative
DSL
s. It needed to support hot code-swaps so it could be updated on the fly. It needed
to run on the cloud, and it needed to be entirely
API
-driven. And we had to build it
without much in the way of resources; we were an engineering team of three.
With these kinds of constraints, we needed a language that gave us leverage. So we
turned to this new language called Clojure. It was a modern, functional language that
ran on the
JVM
. It also promised to solve the problems inherent in concurrent, multi-
threaded code. And it was a Lisp!
I was the architect at this startup, and am now the
without you!
I would also like to thank my parents who started me down this path all those
years ago. I grew up in India at a time when computers were these fantastical things,
out of reach for most people. They took a loan to buy me a computer, instead of buy-
ing their first car, and without that I wouldn’t be here today. So thanks a million,
Mom and Dad!
I also want to acknowledge Ravi Mohan, who in 2001 pointed me to Lisp and to
Paul Graham’s essays. Thanks for showing me the way! And, I guess, thanks also to Paul
Graham, who is an inspiration to many of us.
Thanks to the folks at Runa, for letting me work on this book. Ashok Narasimhan,
the founder, was extremely supportive of the whole effort. The rest of my colleagues
were also very supportive. Specifically, I’d like to thank Robert Berge, Kyle Oba, and
George Jahad for their feedback and encouragement. Finally, I’d like to give special
thanks to Siva Jagadeesan who has supported me throughout this effort in so many ways.
At Manning, I’d like to thank Michael Stephens who provided guidance, feedback,
and support during the many months it took to get the book done, and my develop-
ment editor Susan Harkins for her help and patience and for sticking with the project
www.it-ebooks.info
ACKNOWLEDGMENTS
xvii
from beginning to end. The production team of Linda Recktenwald, Dennis Dalinnik,
Janet Vail, and Mary Piergies also deserves my thanks for turning my manuscript into
the book you are reading today.
Finally, thanks to the following reviewers who read my manuscript during develop-
ment and provided invaluable feedback: Doug Warren, Deepak Vohra, Jeroen
Benckhuijsen, Sivakumar Thyagarajan, Kevin Butler, Jason Rogers, Craig Smith,
Stuart Caborn, Robby O’Connor, Tim Moore, Peter Pavlovich, Federico Tomassetti,
Steve Freeman, Dave Pawson, Joshua Heyer, Keith Kim, Christopher David Stevenson,
Ramnivas Laddad, Andrew Oswald, Pratik Patel, Baishampayan Ghose, Anton
Mazkovoi, Christopher Bailey, and Tom Flaherty.
ABOUT THIS BOOK
xix
How to use this book
Learning Clojure can be quite a leap for a lot of programmers. The drastically differ-
ent syntax, the move from imperative to functional programming, immutability, the
macro system these can be daunting. This book takes a slow and steady approach to
learning the language and the various pieces. It assumes no prior experience with
Lisp or with any functional programming language. It starts out with the absolute
basics, and slowly layers on the different features of the language in a way to make it
all fit together in an intuitive manner. It takes a first-principles approach to all the top-
ics, first explaining why something needs to be done a certain way, and only then talk-
ing about the Clojure way.
Once you get past the basics, the book moves onto real-world usage of Clojure.
You’ll see how to write test-driven Clojure, access data-stores of various kinds (both
relational and the No
SQL
variety), create web services, use messaging to scale your
applications to handle large volumes of traffic, use map/reduce to process data,
understand distributed computing, and build up your business logic through domain-
specific languages (
DSL
s).
To get the most out of the book, I’ve assumed you’re familiar with an
OO
language
like Java, C#, or C++, but no background in Lisp or Clojure is required.
Roadmap
Chapter 1 whets your appetite by giving a high-level description of the language, and
what to expect from the remainder of the book
Chapter 2 goes over the the basics of installing and getting started with Clojure. It
lock-free concurrency. This is a big deal! Your programs can take advantage of multiple
cores without any of the problems associated with traditional multi-threaded code.
Chapter 7 looks at yet another feature of Clojure that is different from most other
programming languages. This is the macro system (not to be confused with C macros
and the like). Clojure essentially provides language-level support for code-generation.
It has a hook in its runtime that allows programmers to transform and generate code
any way they like. This is an incredibly powerful feature that blurs the line between
the language designer and an application programmer. It allows anyone to add fea-
tures to the language.
Chapter 8 shows how you can raise your productivity level significantly by combin-
ing the process of writing test-driven code with the Clojure
REPL
(read-eval-print-loop,
which is Clojure’s command prompt shell). It also addresses mocking and stubbing
functions to enable better unit-testing tactics.
Chapter 9 is about data storage. It not only talks about traditional relational data-
bases such as My
SQL
, but also newer No
SQL
ones such as HBase and Redis. With this
information, you’ll be able to pick the right one for your project, and know how to
access them from Clojure in an idiomatic manner.
Chapter 10 looks at Clojure and the web. In this chapter, you’ll build a simple web-
service framework on your own. You’ll also explore a few open-source projects that make
it trivial to talk
HTTP
in your own projects—whether it is an
API
server or a dynamic website.
s. This will
bring you full circle: we started out in search of a tool that minimizes accidental com-
plexity. Clojure allows you to bend the programming language to your will through
the macro system, and this chapter takes a deeper dive into this feature. You’ll design
an internal
DSL
that will serve as an example of how you can use
DSL
s to drive core
business logic in your Clojure applications.
Code conventions and downloads
All code in the book is presented in a
fixed-width
font
like
this
to separate it from
ordinary text. Code annotations accompany many of the listings, highlighting important
concepts. In some cases, numbered bullets link to explanations that follow the listing.
Please see chapter 2 for instructions on how to download and install Clojure. You
will find the full code for all the examples in the book available for download from the
publisher’s website at http://www.manning.com/ClojureinAction.
Author Online
The purchase of Clojure in Action includes free access to a private forum run by Man-
ning Publications where you can make comments about the book, ask technical ques-
tions, and receive help from the author and other users. You can access and subscribe
to the forum at http://www.manning.com/ClojureinAction. This page provides infor-
tume. Both men and women wear a red or white pillbox cap (called a bareta or crven-
kapa), with a white veil attached to the women’s cap, like in the illustration on this cover.
Dress codes and lifestyles have changed over the last 200 years, and the diversity by
region, so rich at the time, has faded away. It is now hard to tell apart the inhabitants
of different continents, let alone of different hamlets or towns separated by only a few
miles. Perhaps we have traded cultural diversity for a more varied personal life—cer-
tainly for a more varied and fast-paced technological life.
Manning celebrates the inventiveness and initiative of the computer business with
book covers based on the rich diversity of regional life of two centuries ago, brought
back to life by illustrations from old books and collections like this one.
www.it-ebooks.info
Part 1
Getting started
L
earning a new programming language is difficult for several reasons:
there’s a new syntax to learn, some potentially new concepts, and maybe a new
paradigm. Most of all, it’s difficult because a new language makes you feel like a
novice again. Unless you stick with it and gain some experience, even a simple
task will seem like a chore. Your incentive to stick with it, is knowing that the
reward at the end of your labor will be worth the work.
Clojure is such a language. It may appear daunting at first, especially given
the different syntax. State changes work differently in Clojure, so that’s an
adjustment. It’s a functional programming language, so you need to get used to
thinking in terms of functions. If you’re coming from an
OO
background, then
you have to structure your application code in a somewhat different way. These
are only a few of the new things you have to deal with as you learn Clojure.
The reward at the end of all this effort is worth it. Learning Clojure, as is the
case with any Lisp, is worth the effort for the profound enlightenment you’ll