Skip to main content

Good Fences Make Good Functions

May 19, 2005

{cs.r.title}









Contents
A Groovy QuickStart
We're No Longer in Kansas
Does a Fence Keep Things In or Out?
Groovy Closures Man
Closure
References

There's nothing like learning a new language to help clear the coding cobwebs. A while back I was beginning to feel pretty bored with programming. Writing code was growing stale, and I needed something new. A number of scripting languages were getting a fair amount of attention in the press and on the Web, and I thought I might find an answer to my ennui among one of them. After a bit of looking around, I decided upon Groovy.

In some ways, Groovy programming can be as much like Java programming as you want it to be. You can use it as syntactic sugar to simplify some of your least-favorite Java tasks or you can embrace it and explore language constructs unlike anything the typical Java programmer encounters. In this article, you will get some background and a quick introduction to closures.

A Groovy QuickStart

I chose Groovy for several reasons. First, it met the basic need for something new. Second, I was drawn by Groovy's tight relationship to Java. Not only would I have something new, I might also have something I could leverage at work where we've kicked around the idea of adding a scripting feature to our product. It had been a while since I seriously examined any scripting language, and with all of the glowing reports I was hearing about how far scripting had come, I was curious to learn what all the fuss was about.

I started my explorations of Groovy with the excellent Groovy tutorial on the CodeHaus site, edited by Richard Monson-Haefel. The download and installation instructions were clear and easy to follow, and I had my first script entered, displaying "Groovy Baby!" in no time. The tutorial then moved onto declaring and using variables. Groovy is a loosely typed language. Variables are declared and typed by simply assigning them a value. For instance, the following two lines of Groovy declare an integer variable named i and a string variable named s.

i = 5
s = "Groovy Baby!"

Everything was proceeding smoothly. I knew how to enter and run code. Variables were a breeze, and the commands and syntax I had encountered so far in tutorial were basically those of a shorter, more forgiving version of Java. All of this was about to change. The tutorial moved unto a discussion of closures.

On my first read through the section on closures, I must have rushed, because when I finished, I had the idea that I had just been shown how to write functions in Groovy. However, the more I looked at the sample code, the more I realized that closures were not functions, or at least not functions in the usual sense. Suddenly, I found myself in unfamiliar territory.

We're No Longer in Kansas

Like a lot of programmers who find themselves in uncharted waters, I immediately headed over to the Web to do a bit of research. What I discovered surprised me. First, closures have been around for well over twenty years. The Lisp-based Scheme language has supported them since the late 1970s. Second, closures can be found in literally dozens of languages. Groovy and Scheme are not alone in their support of them. Ruby, Smalltalk, Perl, JavaScript, and many more allow closures of one form or another.

Of course. knowing that closures have been around for a while and are supported by a number of languages doesn't tell you what they are. For that, you can turn to the What is Closure page on the famous, or infamous, C2 Wiki. Several definitions of closures are offered on this page, but the most general comes from the inventors of Scheme, Guy Steele and Gerald Sussman: "... a closure is a function that captures the lexical environment in which it was created." Or, as the author of the Wiki page paraphrases it, "... [the closure] runs around and collects all the things in the environment at the time [of its creation]." It's like building a fence around the function and corralling all of the visible variables. In other words, a closure is combination of code and data.

At first glance, this may seem to be a relatively odd construct. Looking at closures in the context of Java programming, it may not seem useful to corral variables in this way. To understand this requires a detour into the world of functional programming and the languages that support this style of development.

A functional programming language is not one that allows subroutines, or "functions." Almost all modern languages support these. Instead, as Benjamin Goldberg states in his short article, "Functional Programming Languages" (PDF), "Functional programming languages are a class of languages designed to reflect the way people think mathematically, rather than reflecting the underlying machine [as is the case in most imperative programming languages such as Java]." That is, functional programming languages are about modeling computations.

While there is frequently debate over whether a particular language qualifies as a functional programming language, there doesn't seem to be much dispute about the basic characteristics. Perhaps the best, or at least the best known, statement of these characteristics can be found in "Why Functional Programming Matters" (PDF), by John Hughes. Hughes lists a number of attributes. The first is actually a simple rule: there are no assignment statements in a functional program, so variables never change once set. The second characteristic is much more interesting; essentially, there are no side effects allowed in functional programs. In other words, functions are limited to computing their results. Since functions are free of side effects, it is irrelevant when they are called. This eliminates the need to worry about the flow of control. In addition, the lack of side effects allows functions to be replaced by values, and values to be substituted by functions.

After thinking about these requirements for a functional language, it becomes clear that closures are a way to meet them. Functions need to capture values at the time of their creation, since there is no other way to assign values to them. Furthermore, functions need to be self-contained entities if they are to avoid side effects. Much of the debate over whether a given language is a functional programming language stems from how loosely or tightly it defines closures.

Does a Fence Keep Things In or Out?

It can be difficult to come to terms with closures. They appear to be a relatively specialized topic, mainly of interest to language implementers. Most of the information I found had more to do with the theory of closures than their practical application. However, the dearth of practical advice is not due to a conspiracy on the part of language designers. Much of the lopsided view of closures may be attributed to developers themselves. As Mike Spille points out in his article "Groovy: First Contact," "In my experience, about 50 percent of software developers go cross-eyed when you use the word 'closure.' They start thinking of bizarre Lisp programs, seas of parentheses, something to do with spices in Indian food, and computer scientist PhDs with pointy glasses and really dirty hair spewing language theory."

Another difficulty I experienced in understanding closures had to do with the variety of definitions I encountered. Each article I read seemed to define the term differently. While a variety of viewpoints can broaden your appreciation of a topic, some of the definitions seem to be a bit self-serving. I get nervous when authors make global statements like "Language X supports true closures."

A third difficulty in understanding closures is the reality that closures are a convenience rather than a necessity. Like recursion, closure is great to have, but there are other ways around the problems it solves, so the need to use and understand them can be avoided. Since there are ways around closures, they remain a little-known, infrequently discussed topic.

In the final analysis, what you make of closures, and how you use them, depends largely upon your point of view.

Groovy Closures Man

Fortunately, closures are relatively simple in Groovy. Let's start with an easy example. To begin, closures are blocks of code contained between curly braces.

greeting = {return "Hello, world.";};
println greeting(); //Displays "Hello, world"

The above closure {return "Hello, world.";} is assigned to the greeting variable, which may be treated like a standard method. When greeting is "called," it returns the string "Hello, world." to the println method, which writes the string to the console.

Adding a parameter to the closure, as in the example below, doesn't change things much. The variable holding the closure continues to look and act much like a standard method.

greeting = {name | return "Hello, " + name;};
println greeting("Shaggy"); //Displays "Hello, Shaggy"

But now, things begin to get a little strange. One of the key features of Groovy closures is that they can return closures.

greeting = {name | 
return {return "Hello, " + name;};
};
sayGreeting = greeting("Shaggy");
println sayGreeting(); //Displays "Hello, Shaggy"

The closure above actually returns a closure that accepts the name parameter, and builds and returns the full greeting string: "Hello, Shaggy". As before, the println method displays the string returned by the closure.

As you can see, closures are easy to create and use in Groovy. They are extremely flexible, accepting any number of parameters, and enclosing any number of statements, though you'll find most closures tend to contain a single line that builds a string it then returns. This simple form of closures really comes in handy when iterating through lists and SQL result sets.

For instance, Groovy's List and Map collections include an each method that accepts a closure as an argument. This makes dumping the values of a collection as easy as shown below.

[1, 2, 3, 5, 7, 11, 13].each {x | println "prime: " + x}

Looping through result sets is just as simple. Given an SQL connection and the result set from a table named foobar with id, name, and address columns, you can easily display the contents of the table to the console.

sql = Sql.newInstance("JDBC_URL", "username", "password",
"JDBC_Driver")
sql.eachRow("SELECT * FROM foobar") {row |
println row.id + " " + row.name + " " + row.address}

In fact, Groovy's closures are the ideal way to package code and data in conveniently passed-around blocks, similar to Java's anonymous classes. But unlike anonymous classes, closures have fewer restrictions on their syntax, scope, and usage. And while it is certainly possible to rewrite all the above samples using standard code, closures add another dimension to Groovy's ease of use.

Closure

I eventually wound my way back to the main task of learning Groovy, and I've come to admire it as a useful tool for all sorts of day-to-day chores. In particular, it's a really great way to do a bit of one-off data manipulation. Reading and writing a file, parsing an XML document, or massaging a JDBC database are all extremely easy to accomplish with Groovy. On the other hand, my unexpected forays have given me new insights into two areas of programming were I was largely ignorant: functional programming and closures. While I am reluctant to claim expertise in any of these areas, I can say without reservation that the cobwebs are definitely gone.

References

Advanced Perl Programming, Chapter 4, by Sriram Srinivasan

"Functional Programming Languages" (PDF), by Benjamin Goldberg

"Groovy Tutorial," CodeHaus Groovy site

"Practically Groovy: JDBC programming with Groovy"

"What is Closure," the C2 Wiki

"Why Functional Programming Matters" (PDF), by John Hughes.

"Groovy: First Contact," by Mike Spille

width="1" height="1" border="0" alt=" " />
Craig Castelaz is a full-time husband and father who programs, teaches, and writes in his second full-time job.