IN ACTION SECOND EDITION Amit Rathore Francis Avila M A N N I N G Praise for the First Edition “An easy-to-read book and a great way to get up to speed with Clojure.” —Craig Smith, Suncorp “A broad but thorough overview of the current state of the art in this exciting new language.” —Tim Moore, Atlassian “Down-to-earth and thorough, just what you need to get building real-world applications.” —Stuart Caborn, BNP Paribas “I love the inclusion of testing and web topics!” —Chris Bailey, HotelTonight “An insightful look at Clojure and its unique position in the JVM family of languages. A good read for anyone trying to ‘get’ Clojure.” —Jason Rogers, MSCI Inc. “Don't just learn Clojure—learn how to build things with it.” —Baishampayan Ghose (BG), Qotd, Inc. “Explains functional programming with Java.” —Doug Warren, Java Web Services “It shows what you can get mixing the power of Java libraries with a pragmatic func- tional language.” —Federico Tomassetti, Politecnico di Torino “A very approachable text and a great introduction to Clojure and Lisp.” —Kevin Butler, HandyApp, LLC “Brings together the features of Clojure and shows how they can be used cohesively to implement a number of engineering solutions. Each solution is stunningly simple and elegant. I highly recommend this book.” —A.B., Amazon reviewer Clojure in Action Second Edition AMIT RATHORE FRANCIS AVILA MANNING SHELTER ISLAND 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 761 Shelter Island, NY 11964 Email: [email protected] ©2016 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 claimed as trademarks. Where those designations appear in the book, and Manning Publications was aware of a trademark claim, the designations have been printed in initial caps or all caps. Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid-free paper, and we exert our best efforts to that end. Recognizing also our responsibility to conserve the resources of our planet, Manning books are printed on paper that is at least 15 percent recycled and processed without the use of elemental chlorine. Manning Publications Co. Development editor: Karen Miller 20 Baldwin Road Technical development editors: Andrew Luly, Michael Williams PO Box 761 Copyeditor: Jodie Allen Shelter Island, NY 11964 Proofreader: Linda Recktenwald Technical proofreader: Joe Smith Typesetter: Dennis Dalinnik Cover designer: Marija Tudor ISBN: 9781617291524 Printed in the United States of America 1 2 3 4 5 6 7 8 9 10 – EBM – 20 19 18 17 16 15 contents preface to the second edition xi preface to the first edition xiii acknowledgments xvi about this book xviii 1 Introducing Clojure 1 1.1 Clojure: What and why? 1 Clojure: A modern Lisp 2 ■ Clojure: Pragmatic functional programming 3 ■ Clojure on the JVM 6 1.2 Language basics 7 Lisp syntax 7 ■ Parentheses 9 1.3 Host interoperation: A JVM crash course 10 Java types, classes, and objects 11 ■ The dot and new operators 12 ■ Threads and concurrency 13 1.4 Summary 14 v vi CONTENTS 2 Clojure elements: Data structures and functions 16 2.1 Coding at the REPL 16 Clojure REPL 17 ■ “Hello, world!” 19 ■ Looking up documentation using doc, find-doc, and apropos 20 A few more points on Clojure syntax 21 2.2 Clojure data structures 24 nil, truth, and falsehood 24 ■ Characters and strings 24 Clojure numbers 25 ■ Symbols and keywords 26 Lists 27 ■ Vectors 29 ■ Maps 31 ■ Sequences 33 2.3 Program structure 34 Functions 34 ■ The let form 35 ■ Side effects with do 37 Reader macros 38 2.4 Program flow 39 Conditionals 39 ■ Logical functions 41 ■ Functional iteration 44 ■ Threading macros 50 2.5 Summary 54 3 Building blocks of Clojure 55 3.1 Metadata 56 Java type hints 58 ■ Java primitive and array types 59 3.2 Java exceptions: try and throw 60 3.3 Functions 62 Defining functions 62 ■ Calling functions 69 Higher-order functions 70 ■ Writing higher-order functions 73 Anonymous functions 76 ■ Keywords and symbols 77 3.4 Scope 80 Vars and binding 80 ■ The let form revisited 85 Lexical closures 86 3.5 Namespaces 87 ns macro 87 ■ Working with namespaces 90 3.6 Destructuring 91 Vector bindings 91 ■ Map bindings 93 3.7 Reader literals 95 3.8 Summary 97 CONTENTS vii 4 Multimethod polymorphism 98 4.1 Polymorphism and its types 98 Parametric polymorphism 99 ■ Ad hoc polymorphism 99 Subtype polymorphism 101 4.2 Polymorphism using multimethods 103 Life without multimethods 103 ■ Ad hoc polymorphism using multimethods 103 ■ Multiple dispatch 106 Subtype polymorphism using multimethods 108 4.3 Summary 114 5 Exploring Clojure and Java interop 116 5.1 Calling Java from Clojure 117 Importing Java classes into Clojure 117 ■ Creating instances 118 ■ Accessing methods and fields 119 Macros and the dot special form 120 ■ Helpful Clojure macros for working with Java 122 ■ Implementing interfaces and extending classes 125 5.2 Compiling Clojure code to Java bytecode 126 Example: A tale of two calculators 126 ■ Creating Java classes and interfaces using gen-class and gen-interface 129 5.3 Calling Clojure from Java 133 5.4 Summary 134 6 State and the concurrent world 135 6.1 The problem with state 136 Common problems with shared state 136 Traditional solution 137 6.2 Separating identities and values 139 Immutable values 140 ■ Objects and time 140 Immutability and concurrency 142 6.3 Clojure’s way 143 Immutability and performance 143 ■ Managed references 144 6.4 Refs 145 Creating refs 145 ■ Mutating refs 145 ■ Software transactional memory 148 6.5 Agents 150 Creating agents 150 ■ Mutating agents 151 ■ Working with agents 152 ■ Side effects in STM transactions 155 viii CONTENTS 6.6 Atoms 155 Creating atoms 155 ■ Mutating atoms 156 6.7 Vars 157 Creating vars and root bindings 157 ■ Var bindings 158 6.8 State and its unified access model 159 Creating 159 ■ Reading 159 ■ Mutation 159 Transactions 160 ■ Watching for mutation 160 6.9 Deciding which reference type to use 161 6.10 Futures and promises 162 Futures 162 ■ Promises 163 6.11 Summary 164 7 Evolving Clojure through macros 166 7.1 Macro basics 167 Textual substitution 167 ■ The unless example 168 Macro templates 171 ■ Recap: Why macros? 176 7.2 Macros from within Clojure 177 comment 177 ■ declare 177 ■ defonce 178 and 178 ■ time 179 7.3 Writing your own macros 180 infix 180 ■ randomly 180 ■ defwebmethod 181 defnn 183 ■ assert-true 184 7.4 Summary 185 8 More on functional programming 186 8.1 Using higher-order functions 187 Collecting results of functions 187 ■ Reducing lists of things 189 ■ Filtering lists of things 191 8.2 Partial application 192 Adapting functions 193 ■ Defining functions 196 8.3 Closures 197 Free variables and closures 197 ■ Delayed computation and closures 198 ■ Closures and objects 199 An object system for Clojure 202 8.4 Summary 215 CONTENTS ix 9 Protocols, records, and types 217 9.1 The expression problem 218 Setting up the example scenario 218 ■ A closer look at the expression problem and some potential solutions 222 Clojure’s multimethods solution 223 9.2 Examining the operations side of the expression problem 225 def-modus-operandi 225 ■ detail-modus-operandi 226 Tracking your modus operandi 227 ■ Error handling and trouble spots in this solution 233 9.3 Examining the data types side of the expression problem with protocols 234 defprotocol and extend-protocol 234 ■ Defining data types with deftype, defrecord, and reify 239 9.4 Summary 245 10 Test-driven development and more 247 10.1 Getting started with TDD: Manipulating dates in strings 248 First assertion 248 ■ month-from and year-from 251 as-string 252 ■ Incrementing and decrementing 253 Refactor mercilessly 255 10.2 Improving tests through mocking and stubbing 256 Example: Expense finders 256 ■ Stubbing 257 Mocking 260 ■ Mocks versus stubs 261 Managing stubbing and mocking state 264 10.3 Organizing tests 265 The testing macro 266 ■ The are macro 266 10.4 Summary 267 11 More macros and DSLs 268 11.1 A quick review of macros 269 11.2 Anaphoric macros 270 The anaphoric if 270 ■ The thread-it macro 273 11.3 Shifting computation to compile time 276 Example: Rotation ciphers without macros 276 Making the compiler work harder 279