Nil Punning (Or Null Pointers Considered Not So Bad)

September 12, 2013

Null pointers are considered by their inventor to be a huge mistake. Clojure inherits its null pointer, called nil in Clojure, from the JVM. In contrast to Java1, Clojure seems to embrace the null pointer. In this post, I'd like to explore how Clojure uses the null pointer in what is often called nil-punning.

Nil-punning has its roots in the very first Lisps, where nil was both false (the boolean value) and the end of a list (the empty list). It was also often used to represent "no answer", as in what is the first element of an empty list. It is called punning because you can use it to mean different things in different contexts.2

In Clojure, nil, as a value, is nearly void of meaning. And it is all pervasive, because it can be returned from any Clojure function or Java method.

Let's go through that last part bit by bit.

  1. It is a value. Java made the mistake of making null a lack of object even though it was pointed to by an object pointer. You can't call methods on it. It is not an object. It has a weird nameless type. Clojure did not make this mistake. It is a first-class value and type3, meaning it can be compared to other values, it can implement protocols, and be used as the key or value of a map, etc. Using nil where it doesn't make sense in Clojure code is usually a type error, not a NullPointerException, just as using a number as a function is a type error.
  1. It is nearly void of meaning. It means "no answer", but not much more. Because of this, it can take whatever form fits the context. With proper wisdom in choosing what form it takes, nil can become an asset instead of a liability. Clojure takes nil-punning to an extreme.

nil can be many things. To name but a few, nil plays false as a boolean. It plays the empty seq as a seq4. It plays the empty map as a map. Because nil has a role to play in most of the major abstractions of core Clojure, it rarely leads you into an error situation. An unexpected nil can surprise a good programmer, just as much as an unexpected Nothing from a Haskell function can bewilder even the most experienced Haskeller. 5 Finding out where a nil came from is the hardest problem that nils present.

  1. It is all-pervasive. nils are normal parts of Clojure programs. They are not anomalous as in Java, where you often have to check it everywhere. This means it is always on the experienced programmer's mind. nils flow like water through s-expressions.

first has nothing to return if the seq is empty, and so it returns nil. Because nil is a seq, first works on nil, and returns nil. 6. rest works on nil as well, because nil is a seq.

These examples show the best of nil-punning. When nil-punning works right, nils are expected and they give the expected results.

nil is everywhere, but it can be used mostly everywhere as well--without error and often with exactly the desired result. There are many abstractions that nil does not participate in (for instance IFn, which is Clojure's interface for things that can be called like functions). In these places, nil can present a problem--a problem of type, the same as if you tried to call a number as a function.

The best thing to do, in my experience, is simply to wrap the expression in a (when ) to catch the nil cases, if appropriate, while also preserving it. Otherwise, perhaps letting the Exception bubble up is the best answer. If you got a nil where you couldn't use one, the stack trace is probably your best clue to where it came from.

After a bit of experience with Clojure, I rarely have difficult problems with out-of-place nils in pure Clojure code. However, there is often some Java interop--namely, calling Java methods directly--that will cause a NullPointerException if the object of the method call is nil. In these cases, wrapping a Java method call in a (when ) is often appropriate. But sometimes not, and the NullPointerException is welcome.

There are some decisions in Clojure that I think make poor use of nil-punning. These places actually make working with Clojure more difficult than they need to be. For instance, (str nil) is the empty string. Printing this out prints nothing--a form of silence, which is rarely what you want so you have to check for nils in these cases. But nil is not the empty string, like it is the empty seq. (clojure.string/trim nil) throws a NullPointerException. This is inconsistent behavior. When nil acts inconsistently, nil-punning does not work right. nils need to be checked. In the worst cases, nils fail silently. While I have learned to deal with these situations, they are a wart on the language. The fact that nils are so common does help surface the bugs sooner. A small consolation.

Let me make it clear: null pointers are still a costly problem in Clojure. But I can make a claim similar to what Haskellers claim about the type system: nil-punning eliminates a certain class of errors. A fortuitous set of decisions in Clojure has reduced the magnitude of the problem. And some decisions have made the problem worse by hiding it. In general, I find that by embracing nil-punning, my code gets better.

Learn Functional Programming using Clojure with screencasts, visual aids, and interactive exercises
Learn more

You might also like


  1. I don't mean to pick on Java alone. I just wanted to be specific.

  2. Note that this is very different from weak typing as you find in Javascript or Python. Nil-punning is more like polymorphism.

  3. The type of nil is nil

  4. Clojure's core is built on several small, powerful abstractions. The most prominent abstraction is seq, which stands for sequence. seq basically has two operations, first and rest. The most obvious use for them is to iterate through items of a collection. There are built-in implementations for lists, vectors, sets, hashmaps, and even strings. But anything that has a notion of sequential values can implement seq, including Java Iterators. I would also like to posit that the most important and often overlooked implementation of seq is for nil itself.

  5. Even the best Haskellers complain about not knowing where a Nothing came from.

  6. You might look at this as nil-preserving behavior--much like the Nothing-preserving behavior of the Maybe Monad

The Parts of Ring

February 18, 2015

Summary: Ring, the Clojure Web library, defines three main concepts that you use to construct web applications.

Ring is the center of the Clojure web universe. It's not the only option in town, but the other options refer to Ring to say how they are different. Understanding Ring will help you learn any other web system in Clojure.

Ring has three main concepts that work together to build a web application.

  1. Adapters
  2. Handlers
  3. Middleware

Adapters

I like to think of Ring Adapters as plug adapters. When you go to a different continent, you often have to adapt the holes in the electical outlet to fit your cords. Ring Adapters let you convert different web server implementations into a standard Ring Request/Response format. That way, all of your code is standardized to the Ring format. Your code can travel into any kind of server as long as an adapter exists.

There are Ring Adapters for many existing servers.

And more.

Handlers

Handlers do the work of your application. They are like the computer. They are just Clojure functions. HTTP is basically a request/response protocol that maps well to functions, which are just a protocol from argument to return value. Handlers take a Ring Request and return a Ring Response. They should do whatever logic is necessary for your application.

Middleware

Middleware are the voltage converters. Here in North America, wall sockets run at 120 volts, which is different from almost everywhere. In order to run an appliance from elsewhere, you not only need to adapt the socket, you also need to transform the current to a compatible voltage. Middleware are often used to convert the incoming request in some standard way. For instance, there is middleware to parse a JSON body into a Clojure map and store it away in the request.

The transformer also "cleans up" the current. Voltage spikes are evened out so they never get to the computer. Middleware can similarly protect a handler by making sure the browser is logged in.

The analogy kind of breaks down, because middleware can do work (like the computer). Middleware are the hardest part of the Ring idea. They're not hard because the concept is hard. They're hard because they require design decisions. If all you had were Adapters and Handlers, you wouldn't have to think about where to put your logic. It would all go in the Handlers.

But there would be a lot of duplicated logic in your handlers. Authentication, routing, content-type switching, all of these things are done the same way over and over. It's the perfect problem for a little higher order programming. That's essentially what Middleware is.

Ring Middleware are functions that take a Handler and return a new Handler. Since Handlers are functions, Middleware are higher-order functions. The transformer on your computer's power cord takes a machine that requires a certain current and turns it into a machine that takes a different current. Middleware are used to do all sorts of things.

So, for instance, there's a Middleware called Prone that captures exceptions in the Handler and displays them in a nice format. Prone is a function that takes a Handler and returns a new Handler that catches exceptions and returns a different Ring Response in that case. Or you have Middleware that handle session cookies. The Middleware take a Handler and return a new Handler that understands sessions.

My recommendation for what to put in Middleware versus what to put in Handlers is simplest to explain with a graph.

Along the x-axis, we have logic that ranges from HTTP logic (handling header values, query params, etc.) to business logic (which bank account to withdraw from). Along the y-axis, we have how unique the logic is, ranging from highly duplicated to custom. These are the two axes I use to figure out whether it should be in the Handler or the Middleware.

The clear cases are easy. In the upper right corner (red dot), where it's custom business logic, it's definitely in the Handler. In the lower left (blue dot), where it's duplicated HTTP logic, I prefer Middleware. The hard part is in the middle. Somewhere between those two, there's a fine line where a case-by-case decision is required.

Conclusions

Ring is great because it requires so few concepts to capture so much of HTTP. But it's not everything. Standard Ring does not support WebSockets, for instance. Small adaptations are necessary. In general, I think this is a great abstraction. And Ring is so central to Clojure on the Web, it's important to know.

If you want to learn more about Ring and how to construct web applications in Clojure, you should check out LispCast Web Development in Clojure. It's a video course designed to guide you through the major libraries used for web development. You'll learn how to build Clojure web applications from existing and custom parts. You build Middleware to make your application adapt to browser limitations. And if you sign up below, you'll get a handy Ring Spec reference sheet, which specifies the Request and Response formats.

You might also like

Pre-conj Prep 2014

September 20, 2014

Prepare for the conj

People have been asking me how they can get ready for all of the great talks lined up for Clojure/conj. There are many topics, and people are feeling overwhelmed. They might know about some of the ideas, but not all of them.

Wouldn't it be nice to do just a little homework before the conj so that you would be sure to maximize your understanding and be able to participate in the conversations afterward?

Unfortunately, googling any topic reveals lots of material, and it's not always the best. It would take hours to sift through the background material for just one topic.

That's why I am publishing the Pre-conj Prep. Each day, I will send you one or two things to read or watch (whichever is better) to get up to speed on the topics of the talks (which are listed on the Clojure/conj speakers page). I'm used to finding great content for the Clojure Gazette, so you can be sure it will be helpful.

Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media. That rich context is what Pre-conj Prep is about. I want to enhance everyone's experience at the conj by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

There are 18 talks listed. After I go through all of them (that will take 18 days), I will go further than the published topics into other helpful stuff to get ready for a great conj. I am trying to get interviews with the speakers, restaurant/event/city guides, and more, to make the conference a special one.

Sign up below

Once you sign up, you'll start receiving the emails, starting with the first, one each day. It's a great way to get ready and excited for the conference.

The conj is a single-track conference, which means all talks happen in series in a single auditorium. The advantage of that is that everyone has a very similar experience. We all see the same talks (unless you skip one). The disadvantage is that you can't choose a different talk if you don't know about a topic. Preparation is key to having a great experience.

As you probably know, conferences are social events. The talks are mostly an excuse to get together, meet each other, and talk about Clojure. The conversations that happen after a talk can be very rewarding. But if you don't understand why the topic is important, you may feel left out. Don't let that happen! You're travelling far and paying (or expensing) lots for the ticket, hotel, and travel. Make the most of it!

Clojure/conj is a conference organized and hosted by Cognitect. This email list is in no way official. It is not sponsored by nor affiliated with Clojure/conj or Cognitect. It is simply me curating and organizing public information about the conference.

You might also like

Pre-West Prep 2015

March 17, 2015

Prepare for Clojure/West

People have been asking me how they can get ready for all of the great talks lined up for Clojure/West. There are many topics, and people are feeling overwhelmed. They might know about some of the ideas, but not all of them.

Wouldn't it be nice to do just a little homework before the conference so that you would be sure to maximize your understanding and be able to participate in the conversations afterward?

Unfortunately, googling any topic reveals lots of material, and it's not always the best. It would take hours to sift through the background material for just one topic.

That's why I am publishing the Pre-West Prep. Each day, I will send you one or two things to read or watch (whichever is better) to get up to speed on the topics of the talks (which are listed on the Clojure/West speakers page). I'm used to finding great content for the Clojure Gazette, so you can be sure it will be helpful.

Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media. That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

There are 33 talks listed and not much time to publish all of them, so I will have to multiple ones per day. I've got Nola Stowe helping me write the summaries and interviews! If you'd like to help, !

Sign up below

Once you sign up, you'll start receiving the emails, starting with the first, one (or more) each day. It's a great way to get ready and excited for the conference.

Clojure/West is a two-track conference, which means often you must choose between two equally awesome talks. You will miss some talks. Preparation is key to having a great experience.

As you probably know, conferences are social events. The talks are mostly an excuse to get together, meet each other, and talk about Clojure. The conversations that happen after a talk can be very rewarding. But if you don't understand why the topic is important, you may feel left out. Don't let that happen! You're travelling far and paying (or expensing) lots for the ticket, hotel, and travel. Make the most of it!

Clojure/West is a conference organized and hosted by Cognitect. This email list is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and other helpers) curating and organizing public information about the conference.

You might also like

Pre-West Interview: Anthony Marcar

April 10, 2015

Introduction

Anthony Marcar generously agreed to do an interview about his talk at Clojure/West. The background to the talk is available, if you like.

Interview

LispCast: How did you get into Clojure?

Anthony Marcar: About 4 years ago, I decided that java wasn’t cutting it for me. I needed a new language, but I wanted to be on the JVM. So Scala and Clojure were the obvious contenders. I decided to spend 3 months building an online card game in both languages to see which I liked more. Scala at first was easier to get into, whereas Clojure was thoroughly alien. But over time, In Scala, I found I was spending more time building abstract Type graphs and waiting for compiles to finish, whereas in Clojure I was having a lot of fun and moving faster. I also loved the emphasis on immutability in Clojure. After that I was hooked.

LC: Clojure is relatively new, so you don't really get many experience reports of large production systems. When you hear someone talking about Clojure who has used it maybe only hobby projects or small projects, what are the common things that strike you as untrue?

AM: I don’t know if "untrue" is the right way to put it, but things people generally haven’t thought about before embarking on larger Clojure projects are things like how do you deploy your application, how do you go about logging and monitoring? How do you protect your application from going down if downstream dependencies start timing out? And how do you grow a code base across multiple projects? There still aren’t many resources in the Clojure space to answer these kinds of questions.

LC: Have you had experience bringing programmers who don't know Clojure onto your team? What were the challenges? What surprised you?

AM: Yes I have had rubyists, node.js and python people join the team. Not surprisingly the JVM was a big challenge. Things like the local maven repository, logging, and common java libraries can be hard to grasp. I was however surprised how easily everyone picked up on Clojure’s fundamentals such as immutability. I guess it’s because that’s what attracted them to the language in the first place.

LC: Do you think Clojure is a good fit for large companies with lots of software?

AM: Clojure is great for large companies. I think it’s greatest asset is its focus on data structures. In big companies, this is a big deal as there are layers and layers of legacy systems, each with their own outdated data formats and protocols. Clojure's focus on data transformations and concurrency makes it perfect for working with many different services to produce the right business outcome. That, combined with the the fact that it runs on the JVM makes it perfect for large companies.

LC: Do you have any advice for the folks out there working for big companies who want to introduce Clojure to their work?

AM: If you want to introduce Clojure at a large company, get ready for a very tough road ahead. Work from both the bottom and top of the organization. Try and find the engineers who are always looking at new technologies. The kind who get home and build side projects. Then infect them. At the same time, scour the organization for VPs, or SVPs who "get" technologists. Buy them a beer. Ask them to be a champion for you, to protect you every time a more "traditional" team tries to block your progress. You’ll need all the help you can get and will have to work well past your normal hours, but it’s worth it.

If you want to take a shortcut, build a company that does Clojure, and then get acquired by said big company ;)

LC: Is there anything else you'd like to add?

AM: All I would add is that working in Clojure is extremely fun. If you’re not already working in it full time, go and apply for a job somewhere where you can!

LC: If Clojure were a food, what food would it be?

AM: An ice cream sandwich. Because it’s awesome. That is all.


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like

Pre-West Prep: John Hume

March 29, 2015

This summary was graciously written by Nola Stowe. She's a programmer, the co-founder of DevChix, and a prolific teacher. She recently ran ClojureBridge Austin. Please shout out to her and say thanks!

Talk: Life of a clojure expression: a quick tour of clojure internals

John Hume's talk at Clojure/West is about Clojure internals.

Background

You can get a lot done in Clojure without understanding much about its internals. But when your code doesn't do what you expect, whether in terms of behavior or performance, it can be extremely useful to dig into the underlying Java code.

John's presentation will walk the audience through some of that code by following a simple map-literal expression through Clojure's reader and analyzer, particularly focusing on code generation in clojure.lang.Compiler, and then onto runtime evaluation. The hope is that you'll come out of the talk better able to analyze what's really happening in your own Clojure code.

About John Hume

Github - Twitter - Website


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like

Pre-West Prep: Nathaniel Smith and Ruth Linehan

April 04, 2015

Talk: One Binder to Rule Them All: Introduction to Trapperkeeper

Nathaniel Smith and Ruth Linehan's talk at Clojure/West is about Trapperkeeper, a Clojure services framework.

Background

Trapperkeeper is PuppetLabs' application services framework for Clojure and other JVM languages. It provides a coherent set of core services and a means for you to define new services. Those services can depend on each other and can be configured through standard config files. As applications become bigger and more complex, standardizing on a configuration mechanism and communication medium is a must.

As background, I suggest you read the intro article and the more technical follow-up article.

About Nathaniel Smith

Homepage - GitHub - Twitter

About Ruth Linehan

GitHub - Twitter


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like

Pre-West Prep: Sean Johnson

April 06, 2015

Talk: Pattern Matching in Clojure: Best Practices

Sean Johnson's talk at Clojure/West is about pattern matching in Clojure.

Background

The built-in pattern matching in Clojure is not as powerful as in Haskell and Erlang. But, being a Lisp, it's easy to write a pattern matching macro. Which has been done, it's called core.match, and it's great. This talk is an experience report from using pattern matching in Clojure. Check out Pattern Matching & Predicate Dispatch, a talk by core.match's creator, David Nolen.

About Sean Johnson

Homepage - Twitter - GitHub


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like

Pre-West Prep: Soren Macbeth

April 06, 2015

Talk: Data Science on Clojure

Soren Macbeth's talk at Clojure/West is about data crunching in Clojure.

Background

Clojure's prowess in the world of data and distributed systems is pretty awesome. This talk is about two open source libraries for crunching lots of data in Clojure. One is called marceline, the other is flambo. Both are wrappers for distributed computation libraries. For background, you may want to watch a talk by Nathan Marz on Storm.

About Soren Macbeth

Homepage - Twitter - GitHub


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like

Pre-West Prep: Tom Faulhaber

April 06, 2015

Talk: Creating Beautiful Spreadsheets with Data and Templates

Tom Faulhaber's talk at Clojure/West is about generating Excel sheets in Clojure.

Background

People are using Clojure for some really interesting work. This one is about using Excel as an output format. It's richer by far than CSV, and it can let non-programmers explore data in a way no other tool can. Tom Faulhaber has created a library for filling in Excel templates with Clojure data. See his blog post for more info.

About Tom Faulhaber

Homepage - Twitter - GitHub


This post is one of a series called Pre-West Prep, which is also published by email. It's all about getting ready for the upcoming Clojure/West, organized by Cognitect. Conferences are ongoing conversations and explorations. Speakers discuss trends, best practices, and the future by drawing on the rich context built up in past conferences and other media.

That rich context is what Pre-West Prep is about. I want to enhance everyone's experience at the conference by surfacing that context. With just a little homework, we can be better prepared to understand and enjoy the talks and the hallway conversations.

Clojure/West is a conference organized and hosted by Cognitect. This information is in no way official. It is not sponsored by nor affiliated with Clojure/West or Cognitect. It is simply me (and helpers) curating and organizing public information about the conference.

You might also like