Reader small image

You're reading from  The Clojure Workshop

Product typeBook
Published inJan 2020
Reading LevelBeginner
PublisherPackt
ISBN-139781838825485
Edition1st Edition
Languages
Right arrow
Authors (5):
Joseph Fahey
Joseph Fahey
author image
Joseph Fahey

Joseph Fahey has been a developer for nearly two decades. He got his start in the Digital Humanities in the early 2000s. Ever since then, he has been trying to hone his skills and expand his inventory of techniques. This lead him to Common Lisp and then to Clojure when it was first introduced. As an independent developer, Joseph was able to quickly start using Clojure professionally. These days, Joseph gets to write Clojure for his day job at Empear AB.
Read more about Joseph Fahey

Thomas Haratyk
Thomas Haratyk
author image
Thomas Haratyk

Thomas Haratyk graduated from Lille University of Science and Technology and has been a professional programmer for nine years. After studying computer science and starting his career in France, he is now working as a consultant in London, helping start-ups develop their products and scale their platforms with Clojure, Ruby, and modern JavaScript.
Read more about Thomas Haratyk

Scott McCaughie
Scott McCaughie
author image
Scott McCaughie

Scott McCaughie lives near Glasgow, Scotland where he works as a senior Clojure developer for Previse, a Fintech startup aiming to solve the problem of slow payments in the B2B space. Having graduated from Heriot-Watt University, his first 6 years were spent building out Risk and PnL systems for JP Morgan. A fortuitous offer of a role learning and writing Clojure came up and he jumped at the chance. 5 years of coding later and it's the best career decision he's made. In his spare time, Scott is an avid reader, enjoys behavioral psychology and financial independence podcasts, and keeps fit by commuting by bike, running, climbing, hill walking, snowboarding. You get the picture!
Read more about Scott McCaughie

Yehonathan Sharvit
Yehonathan Sharvit
author image
Yehonathan Sharvit

Yehonathan Sharvit has been a software developer since 2001. He discovered functional programming in 2009. It has profoundly changed his view of programming and his coding style. He loves to share his discoveries and his expertise. He has been giving courses on Clojure and JavaScript since 2016. He holds a master's degree in Mathematics.
Read more about Yehonathan Sharvit

Konrad Szydlo
Konrad Szydlo
author image
Konrad Szydlo

Konrad Szydlo is a psychology and computing graduate from Bournemouth University. He has worked with Clojure for the last 8 years. Since January 2016, he has worked as a software engineer and team leader at Retailic, responsible for building a website for the biggest royalty program in Poland. Prior to this, he worked as a developer with Sky, developing e-commerce and sports applications, where he used Ruby, Java, and PHP. He is also listed in the Top 75 Datomic developers on GitHub.
Read more about Konrad Szydlo

View More author details
Right arrow

11. Macros

Learning objectives

In this chapter, you will learn how Clojure macros work and how to write them. Macros are a very powerful feature of Clojure that simply does not exist in many other non-Lisp languages. Writing macros requires learning some new concepts and some new skills. This chapter will take you through the basic concepts: distinguishing between compile-time and run-time execution, quoting strategies and macro hygiene.

By the end of this chapter, you will be able to automatically generate functions and craft custom environments to streamline your code.

Introduction

Macros have been a distinctive feature of Lisps for decades. They are sometimes presented as a superpower native to the world of Lisp. While macros do exist in other languages, for many decades, Lisps have had the most complete macro systems. Why is this? Languages from the Lisp family share the ability to write code that modifies itself. People often talk about "code as data": Lisp programs, with their nested sets of parentheses called s-expressions, are in fact lists. And Lisps, as languages, are good at manipulating lists. The name "Lisp" originally came from "LISt Processor" when the language was first invented in 1958. As a result, Lisps can be made to operate on the code of Lisp programs. Usually, this means that a program modifies its own code.

Note

The term homoiconicity is often applied to Lisps. While the exact meaning of this term depends on who is talking, it generally means that Lisps are written in forms that they can manipulate...

What is a Macro?

A macro is a piece of code that is executed before your code is compiled. The code contained inside a macro call is transformed into something different and then passed on to the compiler. In Clojure, macros are defined by calling defmacro. A call to defmacro looks fairly similar to a call to defn:

(defmacro my-macro
  "Macro for showing how to write macros"
  [param]
  ;;TODO: do something
  )

Despite this apparent similarity, there is a huge difference between macros and functions. Unlike functions, macros are not called at runtime. When your program finally starts running, the macros have already been called. The code they produce has already been included in your program as if you had typed it in yourself:

Figure 11.1: Separating compile time from runtime is the key to understanding macros

Keep this idea in mind while you think about and work with macros: any macro in your code could...

Syntax Quoting

A lot of the art of writing macros lies in mastering the separation between expansion code and output code. A lot of the control over that separation depends on deciding what gets quoted when the macro is expanded and what does not get quoted. The previous example started to reveal the limits of the standard quote special form. Once a list has been quoted, all its symbols and sub-lists are quoted as well. As such, quote is a fairly heavy-handed tool.

For this reason, Clojure, like many Lisps, provides a more sophisticated quoting mechanism called syntax quoting. Syntax quoting uses ', the backtick character, instead of the standard single quote. When used by itself, the backtick has more or less the same behavior as quote: all symbols and sub-lists are quoted by default. The difference is that syntax quoting allows us to mark certain forms, sub-lists, or symbols that should not be quoted.

With syntax quoting, we can simplify our macro from the previous section...

Macros in ClojureScript

The distinction between compile time and runtime is perhaps the most important concept to grasp when learning about macros. Before going further into the consequences of this distinction, it's worth looking at how it affects macros in ClojureScript, where compilation and execution have a slightly more complex relationship than they do in JVM Clojure.

ClojureScript runs in a JavaScript runtime, like the browser or Node.js. This is possible because ClojureScript code is first compiled by the ClojureScript compiler, which is a program written in Clojure and runs on the JVM. This means that ClojureScript programs, once they're compiled and running, no longer have access to the compilation phase.

This has several consequences for working with macros in ClojureScript, the most important of which is that ClojureScript macros cannot be defined in .cljs files

alongside other ClojureScript code. Instead, they are defined in separate files with either...

Macro Hygiene

Like most programming languages, Clojure provides a lot of resources for avoiding name collisions. Namespaces, let bindings, and lexical scope, all help to make it fairly difficult to override variables by choosing the wrong name. Because they operate in a different space, and at a different time, macros have the potential to go around some of those guardrails. Macro hygiene is the art of writing macros that avoid variable capture. Variable capture is what happens when a symbol produced by a macro coincides with a macro in the surrounding environment.

Note

The term variable capture has its origins in other languages of the Lisp family. Unlike Clojure, most Lisps do not have immutable data structures, so the word "variable" is perfectly appropriate. We'll continue to say "variable capture," even though most Clojure "variables" aren't really variables.

Here's a quick example. Earlier in this chapter, we tried to write...

Summary

In this chapter, we've explored Clojure's macro system, as well as many of the issues surrounding macros. By now, you should have a grasp of the fundamental concepts of macros, starting with the difference between compile-time and runtime evaluation, and have a mental model that will allow you to move on to writing your own macros if necessary, or to understand macros that have been written by others. The problems of macro hygiene, variable capture, and double evaluation are at the heart of the macro writing process. Knowing all of this will help you write macros, read macros, and, most of all, decide when to write a macro and when not to.

Regardless of whether or not you go on to use macros to write your own Domain-Specific Languages (DSL) in Clojure, you'll already benefit from Clojure macros. The flexibility they provide allows Clojure to be extended by library authors in ways that would simply be impossible without macros. Many commonly used Clojure libraries...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
The Clojure Workshop
Published in: Jan 2020Publisher: PacktISBN-13: 9781838825485
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.
undefined
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

Authors (5)

author image
Joseph Fahey

Joseph Fahey has been a developer for nearly two decades. He got his start in the Digital Humanities in the early 2000s. Ever since then, he has been trying to hone his skills and expand his inventory of techniques. This lead him to Common Lisp and then to Clojure when it was first introduced. As an independent developer, Joseph was able to quickly start using Clojure professionally. These days, Joseph gets to write Clojure for his day job at Empear AB.
Read more about Joseph Fahey

author image
Thomas Haratyk

Thomas Haratyk graduated from Lille University of Science and Technology and has been a professional programmer for nine years. After studying computer science and starting his career in France, he is now working as a consultant in London, helping start-ups develop their products and scale their platforms with Clojure, Ruby, and modern JavaScript.
Read more about Thomas Haratyk

author image
Scott McCaughie

Scott McCaughie lives near Glasgow, Scotland where he works as a senior Clojure developer for Previse, a Fintech startup aiming to solve the problem of slow payments in the B2B space. Having graduated from Heriot-Watt University, his first 6 years were spent building out Risk and PnL systems for JP Morgan. A fortuitous offer of a role learning and writing Clojure came up and he jumped at the chance. 5 years of coding later and it's the best career decision he's made. In his spare time, Scott is an avid reader, enjoys behavioral psychology and financial independence podcasts, and keeps fit by commuting by bike, running, climbing, hill walking, snowboarding. You get the picture!
Read more about Scott McCaughie

author image
Yehonathan Sharvit

Yehonathan Sharvit has been a software developer since 2001. He discovered functional programming in 2009. It has profoundly changed his view of programming and his coding style. He loves to share his discoveries and his expertise. He has been giving courses on Clojure and JavaScript since 2016. He holds a master's degree in Mathematics.
Read more about Yehonathan Sharvit

author image
Konrad Szydlo

Konrad Szydlo is a psychology and computing graduate from Bournemouth University. He has worked with Clojure for the last 8 years. Since January 2016, he has worked as a software engineer and team leader at Retailic, responsible for building a website for the biggest royalty program in Poland. Prior to this, he worked as a developer with Sky, developing e-commerce and sports applications, where he used Ruby, Java, and PHP. He is also listed in the Top 75 Datomic developers on GitHub.
Read more about Konrad Szydlo