First-Class Functions - Becoming Functional (2014)

Becoming Functional (2014)

Chapter 2. First-Class Functions

Although most functional programming books present immutable variables first, we’re going to start with first-class functions. My hope is that as you read through this chapter, you will see ways in which you could start using some of these ideas at your job tomorrow.

First-class functions are functions treated as objects themselves, meaning we can pass a function as a parameter to another function, return a function from a function, or store a function in a variable. This is one of the most useful features in functional programming, and also one of the most difficult to learn to use effectively.

Introduction to XXY

Welcome to your new company, XXY. You have been hired for your functional programming skills, which your boss would like to use in order to make the company’s code more “functional.” XXY currently uses Java but is interested in some newer languages such as Groovy or Scala. Although you have some ideas, you have been told that the company can’t afford to just “throw away all of its current code and start over.”

All right, it’s time to get down to business. You have been tasked with adding a new function to return a list of enabled customers’ addresses. Your boss tells you the code should be added to the Customer.java file, where XXY is already implementing the same type of functionality (seeExample 2-1).

Example 2-1. Customer.java file contents

importjava.util.ArrayList;

importjava.util.List;

publicclassCustomer {

staticpublic ArrayList<Customer> allCustomers = new ArrayList<Customer>();

public Integer id = 0;

public String name = "";

public String address = "";

public String state = "";

public String primaryContact = "";

public String domain = "";

public Boolean enabled = true;

public Customer() {}

publicstatic List<String> getEnabledCustomerNames() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(customer.name);

}

}

return outList;

}

publicstatic List<String> getEnabledCustomerStates() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(customer.state);

}

}

return outList;

}

publicstatic List<String> getEnabledCustomerPrimaryContacts() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(customer.primaryContact);

}

}

return outList;

}

publicstatic List<String> getEnabledCustomerDomains() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(customer.domain);

}

}

return outList;

}

/* TODO: Add a main function */

}

There are four almost identical functions in the preceding example. Each function has:

§ The creation of an array list

§ A for loop

§ An if statement

§ A return statement

We have six lines of code duplicated per function. That’s 18 lines of duplicated code: one of those functions started this, which means we have 12 lines that have been copied and pasted.

INTRODUCTION TO THE DRY PRINCIPLE

The DRY (Don’t Repeat Yourself) principle has been around for many years; the concept is that we should not be duplicating lines of code. This makes the code harder to maintain. But why is that the case?

Think about what happens if you duplicate a function multiple times. Now imagine that you just found a bug in one of those functions; you’ll have to go through however many other functions to see if that same bug exists.

What would happen if you renamed enabled, or if you decided to deprecate the enabled field for something else? Now you have four functions that need to be rewritten. Could you imagine if you got a request for the alternate getDisabled* functions? This explodes to eight copied-and-pasted functions.

You start getting a little light-headed thinking, “What have I gotten myself into?” You take a deep breath and realize that you can do this; you’re a functional programmer and eradicating copy and paste is what you do! Our first step is to begin thinking of functions as objects.

Functions as Objects

As we said before, first-class functions can be both passed and returned from another function. Let’s begin by thinking about what a function is. In its most general form, a function is merely a way to encapsulate a piece of work so that we can easily reference it again—that is, nothing more than a macro.

What are the components of a function? Functions are made up of a name that is used to identify the function, a parameter list containing objects to operate on, a body where we transform the parameters, and finally a return to specify the result.

Let’s break down the getEnabledCustomerNames function from the Customer.java file (see Example 2-2). As we can see, the function name is getEnabledCustomerNames, the parameter list is empty, and the body contains code that iterates over the Customer.allCustomers list, adding the customer.name field to an output list only if the customer is enabled. Finally, our return is our output list, outList.

Example 2-2. Customer.getEnabledCustomerNames

publicstatic List<String> getEnabledCustomerNames() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(customer.name);

}

}

return outList;

}

Refactoring Using If-Else Structures

Let’s write a new function that performs the same functionality from Example 2-2 (excluding the addition of the field to the outList) and call it getEnabledCustomerField. For the moment, we’ll just add a comment //Placeholder where we were grabbing the customer.name field and appending it to outList.

The first thing to do is to create a new ArrayList at the top of our function:

publicstatic List<String> getEnabledCustomerField() {

ArrayList<String> outList = new ArrayList<String>();

We then create the for loop and the if statement, which checks for the customer being enabled:

for(Cutomer customer : Customer.allCustomers) {

if(customer.enabled) {

As I mentioned, we’re going to put in a placeholder where we were originally appending the field value to our list. We then close out the if structure and for loop, returning the new outList:

//Placeholder

}

}

return outList;

}

Let’s put all of this together to create our new getEnabledCustomerField method, as shown in Example 2-3.

Example 2-3. getEnabledCustomerField with placeholder

publicstatic List<String> getEnabledCustomerField() {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

//Placeholder

}

}

return outList;

}

Because we know all the possible fields that we’re looking for, let’s take a new parameter, the field name we’re looking for. We’ll then add an if structure to append our list with the value of the field we are looking for, as shown in Example 2-4.

Example 2-4. getEnabledCustomerField with if structure

publicstatic List<String> getEnabledCustomerField(String field) {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

if(field == "name") {

outList.add(customer.name);

} elseif(field == "state") {

outList.add(customer.state);

} elseif(field == "primaryContact") {

outList.add(customer.primaryContact);

} elseif(field == "domain") {

outList.add(customer.domain);

} elseif(field == "address") {

outList.add(customer.address);

} else {

thrownew IllegalArgumentException("Unknown field");

}

}

}

return outList;

}

TYPE SAFETY BY EXCEPTION

In Example 2-4, we’re throwing an IllegalArgumentException to ensure type safety. This means that we are throwing an exception if the field is not one of our predefined fields.

Why is this such a bad idea? You are avoiding type safety since you are relying on string comparisons for field accessors. You are also now relying on someone spelling it correctly both in the if structure as well as when he calls the method itself.

There are other ways to ensure type safety, such as using enumerations containing a list of valid values and matching the corresponding enumeration in our if/else structure.

OK, we’ve just consolidated the looping functionality to exist in only one function. So what happens if we keep adding fields to extract? We’ll keep adding field checks to the if/else structure, which means we’ll eventually end up with an unmanageable if structure. What if we could provide a simple function to extract the field we want from the object itself?

Refactoring Using Function Objects to Extract Fields

We’re going to be using Java interfaces to create an abstraction of a function that we could pass to another function. Many other languages, including the proposals in Java 8, offer functions as objects; as of this writing, however, Java 7 is the currently released and stable version. Thus, we are going to use interfaces to create functionality that we can pass to other functions.

You might be familiar with the Runnable interface, with which you encapsulate some function that you want to execute on a thread. We have similar functionality here, except we need a function that can take an object (the object from which we want to extract a field) and return an object (the value of the field).

MATH WARNING

Let’s assume that we have a function, f, that does some computation referencing the function a and returns the value:

Math Warning

Now, let’s assume that we want to rewrite f so that instead of calling a we call b. Well, to continue rewriting these functions as f and f' (and so on) would be duplication. Lambda calculus introduced the concept of passing a function to a function. So, instead of calling the function a, what if we could pass it in? Let’s redefine f:

Math Warning

Now, we can make a call into our function using either a or b fairly easily. Let’s see the call and substitute our values:

Math Warning

What should our function take as an argument? Let’s look where it will be called. It will be replacing the giant if structure. The purpose of our function is to convert a Customer record into a String, which means our new function will take a Customer object and return a String. Let’s build our interface definition.

The first thing that we do is give our interface a name:

privateinterfaceConversionFunction {

Next we’ll define our method, which is the entry point into our function. As I said before, it will take a Customer and return a String:

public String call(Customer customer);

}

Example 2-5 shows the entirety of the ConversionFunction definition.

Example 2-5. ConversionFunction definition

privateinterfaceConversionFunction {

public String call(Customer customer);

}

We’ll want to make this interface public later, moving it into its own file and making it a little more generic. But for now, let’s focus on using this new ConversionFunction interface by replacing our giant if structure.

First, we replace the field parameter with a ConversionFunction object. We can then replace the giant if/else structure with a call to func.call(customer). Remember, the call method inside the ConversionFunction interface will be performing the conversion for us. All we need to do is execute call and add the result. Check out the code in Example 2-6.

Example 2-6. getEnabledCustomerField definition with ConversionFunction

publicstatic List<String> getEnabledCustomerField(ConversionFunction func) {

ArrayList<String> outList = new ArrayList<String>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(func.call(customer));

}

}

return outList;

}

Now that we’re starting to think more functionally, let’s see what one of those ConversionFunctions would look like. Just return the field that you want to extract. In the following example, the CustomerAddress class allows us to take a Customer and return the address field:

staticprivateclassCustomerAddressimplements ConversionFunction {

public String call(Customer customer) { return customer.address; }

}

Let’s go ahead and make your boss happy now by implementing the getEnabledCustomerAddresses function he wanted. We can create our getEnabledCustomerAddresses function, which will call our new getEnabledCustomerField method and pass it a conversion function. Now if the definition of enabled ever changes, we only have to fix it in one place:

publicstatic List<String> getEnabledCustomerAddresses() {

return Customer.getEnabledCustomerField(new CustomerAddress());

}

Although we don’t need to do it yet, what would happen if we needed to get a list of all enabled customers? Well, our current interface really doesn’t help there, because our interface is strictly defined to take a Customer object and return a String. We should modify our interface to be more abstract by using generic typing. Let’s start by renaming our ConversionFunction to Function1, taking two type parameters (A1 and B, which are the type of the parameter and the return, respectively). Our new function is shown in Example 2-7.

Example 2-7. Interface for encapsulating a function taking one argument

publicinterfaceFunction1<A1,B> {

public B call(A1 in1);

}

TYPE PARAMETER NAMING CONVENTION

Why are we naming this interface Function1? Well, we’re naming it Function because it is going to be wrapping a function. The number 1 comes from the number of parameters that the function itself will take. Our generic typing seems a little odd because we have two parameters, but remember that the final parameter is the return type.

So, what if we needed a function that takes two arguments (shown in Example 2-8) or four arguments (shown in Example 2-9)?

Example 2-8. Interface for encapsulating a function taking two arguments

publicinterfaceFunction2<A1,A2,B> {

public B call(A1, in1,A2 in2);

}

Example 2-9. Interface for encapsulating a function taking four arguments

publicinterfaceFunction4<A1,A2,A3,A4,B> {

public B call(A1 in1,A2 in2,A3 in3,A4 in4);

}

Next, we’ll update the CustomerAddress inheritance to be Function1<Customer,String>.

staticprivateclassCustomerAddressimplements Function1<Customer, String> {

public String call(Customer customer) { return customer.address; }

}

We then update getEnabledCustomerField to take a Function1. Our first parameter will always be a Customer, but our second parameter will change, so we’ll leave that as B. We then parameterize the getEnabledCustomerField method to take a parameter B and finally update our return type for getEnabledCustomerField to return a List of type B (see Example 2-10).

Example 2-10. getEnabledCustomerField with generic typed Function1

publicstatic <B> List<B> getEnabledCustomerField(Function1<Customer,B> func) {

ArrayList<B> outList = new ArrayList<B>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(func.call(customer));

}

}

return outList;

}

Now that you’ve done what your boss asked, it’s time to convert all the other getEnabledCustomer* functions. We’ll just create a new class that implements our Function1 interface and then update the getEnabledCustomer* method to call theCustomer.getEnabledCustomerField() method with a new instance of the appropriate class. Go ahead and refactor the rest of the file and then check out the code in Example 2-11 to see how it looks.

Example 2-11. Customer.java file after initial refactoring

importjava.util.ArrayList;

importjava.util.List;

publicclassCustomer {

staticpublic ArrayList<Customer> allCustomers = new ArrayList<Customer>();

public Integer id = 0;

public String name = "";

public String address = "";

public String state = "";

public String primaryContact = "";

public String domain = "";

public Boolean enabled = true;

public Customer() {}

privateinterfaceFunction1<A1,B> {

public B call(A1 in1);

}

staticprivateclassCustomerAddressimplements Function1<Customer, String> {

public String call(Customer customer) { return customer.address; }

}

staticprivateclassCustomerNameimplements Function1<Customer, String> {

public String call(Customer customer) { return customer.name; }

}

staticprivateclassCustomerStateimplements Function1<Customer, String> {

public String call(Customer customer) { return customer.state; }

}

staticprivateclassCustomerPrimaryContactimplements Function1<Customer, String>

{

public String call(Customer customer) { return customer.primaryContact; }

}

staticprivateclassCustomerDomainimplements Function1<Customer, String> {

public String call(Customer customer) { return customer.domain; }

}

staticprivateclassCustomerAsCustomerimplements Function1<Customer, Customer> {

public String call(Customer customer) { return customer; }

}

publicstatic List<String> getEnabledCustomerAddresses() {

return Customer.getEnabledCustomerField(new CustomerAddress());

}

publicstatic List<String> getEnabledCustomerNames() {

return Customer.getEnabledCustomerField(new CustomerName());

}

publicstatic List<String> getEnabledCustomerStates() {

return Customer.getEnabledCustomerField(new CustomerState());

}

publicstatic List<String> getEnabledCustomerPrimaryContacts() {

return Customer.getEnabledCustomerField(new CustomerPrimaryContact());

}

publicstatic List<String> getEnabledCustomerDomains() {

return Customer.getEnabledCustomerField(new CustomerDomain());

}

publicstatic <B> List<B> getEnabledCustomerField(Function1<Customer,B> func) {

ArrayList<B> outList = new ArrayList<B>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(func.call(customer));

}

}

return outList;

}

}

Let’s answer our original question of “what would happen if we needed to get a list of all enabled customers?” We can create a new class that takes a customer and returns a customer, as shown in Example 2-12.

Example 2-12. A Customer as Customer class

staticprivateclassCustomerAsCustomerimplements Function1<Customer, Customer> {

public String call(Customer customer) { return customer; }

}

Now, we can call Customer.getEnabledCustomerField(new CustomerAsCustomer()), which gives us a list of all our enabled cutomers. But what if we didn’t want to have to create all of these named classes? What if we didn’t actually need to define full classes? Well, that leads right into the next section on anonymous functions.

Anonymous Functions

Anonymous functions are split into two types: lambda functions and closures. Closures are quite similar to lambdas with a very subtle difference, which we’ll discuss later. As you learned in the previous section, functions are made up of four parts: name, parameter list, body, and return. But what if we didn’t need the name of the function? This is the idea behind anonymous functions: being able to create functions that have a limited scope and need to exist only for a short time.

MATH WARNING

Let’s bring back our function from the beginning of this chapter:

Math Warning

Lambda calculus enables us to create a function without defining it formally. Our function f is a formal definition, but what if we want to pass in a function as the parameter c for something really simple, such as a square of the input? Let’s see that and substitute our variables:

Math Warning

The lambda expression is a function that takes an x parameter and performs the x2 operation. So when we substitute, we can actually replace the entire c(x) definition with the lambda function itself. Let’s simplify the function call a little bit, since we can now evaluate our lambda function:

Math Warning

Back at XXY, your boss is excited to see the company’s code becoming “functional.” However, he’s concerned with the number of extra classes being created and feels they are unnecessary. He’s asked you to clean up the code by reducing the number of inner classes. Luckily, we can do this by using lambda functions.

Lambda Functions

Lambda functions are unnamed functions that contain a parameter list, a body, and a return. In the following getEnabledCustomerAddresses example, let’s try to use an anonymous function (in this case, an anonymous instance of Function1) to get rid of the superfluousCustomerAddress class:

new Function1<Customer, String>() {

public String call(Customer customer) { return customer.address; }

}

Let’s use this anonymous class by sending it to our getEnabledCustomerField function (see Example 2-13). We can now remove the CustomerAddress conversion class.

Example 2-13. getEnabledCustomerAddresses using anonymous Function1

publicstatic List<String> getEnabledCustomerAddresses() {

return Customer.getEnabledCustomerField(new Function1<Customer,String>() {

public String call(Customer customer) { return customer.address; }

});

}

Go ahead and see if you can refactor the rest of the functions; when you’re done, check out Example 2-14 and see how they compare.

Example 2-14. Customer.java file with anonymous classes

importjava.util.ArrayList;

importjava.util.List;

publicclassCustomer {

staticpublic ArrayList<Customer> allCustomers = new ArrayList<Customer>();

public Integer id = 0;

public String name = "";

public String address = "";

public String state = "";

public String primaryContact = "";

public String domain = "";

public Boolean enabled = true;

public Customer() {}

privateinterfaceFunction1<A1,B> {

public B call(A1 in1);

}

publicstatic List<String> getEnabledCustomerAddresses() {

return Customer.getEnabledCustomerField(new Function1<Customer,String>() {

public String call(Customer customer) { return customer.addresses; }

});

}

publicstatic List<String> getEnabledCustomerNames() {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) { return customer.name; }

});

}

publicstatic List<String> getEnabledCustomerStates() {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) { return customer.state; }

});

}

publicstatic List<String> getEnabledCustomerPrimaryContacts() {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) { return customer.primaryContact; }

});

}

publicstatic List<String> getEnabledCustomerDomains() {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) { return customer.domain; }

});

}

publicstatic <B> List<B> getEnabledCustomerField(Function1<Customer,B> func) {

ArrayList<B> outList = new ArrayList<B>();

for(Customer customer : Customer.allCustomers) {

if(customer.enabled) {

outList.add(func.call(customer));

}

}

return outList;

}

}

Your boss is excited by how great a job you’re doing, but he now needs a new piece of functionality. He needs to have his email prepended to the domain of each Customer. As with most strange requests, you just kind of stare blankly at him for a moment and then agree to carry it out.

Your boss then shows you an example of a Customer with the domain xxy.com, which is already defined in the Customer object. “You should be able to just concatenate my email with the domain of each Customer object and be done,” he says. “Something like boss@xxy.com.” You think for a few minutes and realize that it is a perfect time to use closures!

Closures

Closures are much like lambdas, except they reference variables outside the scope of the function. In the simplest explanation, the body references a variable that doesn’t exist in either the body or the parameter list.

Your boss’s request to prepend his email onto customer domains seems like a really simple function to write. We’re going to use our getEnabledCustomerField, and in our anonymous function we’ll prepend “boss@” to the customer domains:

publicstatic List<String> getEnabledCustomerBossesEmail() {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) {

return "boss@" + customer.domain;

}

});

}

But wait—what happens if the president of XXY comes to you and says, “I want my email prepended to the customer domains”? The first idea that comes to you is to copy and paste the function and update it with “president@”. This violates the DRY principle, however, so you should reconsider this approach. What if we were able to bring in a variable that was outside of our class definition? Well, this is a perfect use of a closure.

We know that we’re going to have a name of someone passed into our function getEnabledCustomerSomeoneEmail. This function should have a variable, someone, passed to it. At this point, we can reference the someone variable from inside our anonymous function and create the email address (see Example 2-15).

Example 2-15. getEnabledCustomerSomeoneEmail with final field

publicstatic List<String> getEnabledCustomerSomeoneEmail(final String someone) {

return Customer.getEnabledCustomerField(new Function1<Customer, String>() {

public String call(Customer customer) {

return someone + "@" + customer.domain;

}

});

}

REMEMBER TO MARK CLOSED-OVER VARIABLES AS FINAL

Always remember to mark closed-over variables as final. The Java compiler requires this; otherwise, it will throw a compile-time error of local variable someone is accessed from within inner class: needs to be declared final.

This is still a real closure, which we can tell from Example 2-16. Notice that we have our original Closure variable coming in; we can see the variable printed out (providing us a variable reference) and the contents (which should be a blank string). Next, we set the internal string variable tobar and then create/run our closure (it is a closure because the scope of the t variable is “closed over” and brought into the scope of our runnable).

Upon execution, we print out "bar" as is expected, but notice that the reference is the same! We then set the internal string to baz and exit our closure. The next line in our function is to print out the internal string, which is now "baz" and still has the same reference. Although a very simple example, this is a perfect illustration of how a closure truly works; we have an internal function that closes over a variable outside of its normal scope.

Example 2-16. A closure in Java showing that the variable is actually closed over

publicclassClosure {

public String foo = "";

publicstatic Closure process(final Closure t) {

System.out.println(t.toString() + " = " + t.foo);

t.foo = "bar";

new Runnable() {

publicvoid run() {

System.out.println(t.toString() + " = " + t.foo);

t.foo = "baz";

}

}.run();

System.out.println(t.toString() + " = " + t.foo);

return t;

}

publicstaticvoid main(String[] args) {

process(new Closure());

}

}

Using closures, you can build functions and pass them to other functions while referencing local variables. Think about our example of specifying any name to prepend to customer domains. If we were unable to close over the local variable of someone, we would be forced to create new functions for every name we wanted to prepend. This means we would have quite a bit more code duplication.

Higher-Order Functions

The day you have been dreading has come: your boss has asked you to re-create the functions getEnabledCustomerAddresses, getEnabledCustomerNames, getEnabledCustomerStates, getEnabledCustomerPrimaryContacts, and getEnabledCustomerDomains asgetDisabled style functions. The first way of doing this is to copy and paste the .getEnabledCustomerField method and create a .getDisabledField changing if (customer.enabled) to if (!customer.enabled), as shown in Example 2-17.

Example 2-17. getDisabledField

publicstatic <B> List<B> getDisabledField(Function1<Customer,B> func) {

ArrayList<B> outList = new ArrayList<B>();

for(Customer customer : Customer.allCustomers) {

if (!customer.enabled) {

outList.add(func.call(customer));

}

}

return outList;

}

It should be obvious that, again, we are violating the DRY principle. Let’s extract the test functionality in the if statement so that we can pass it into the function. We will accept a function taking a Customer and returning a Boolean that will tell us whether it should be included. We then replace our if with the evaluation of the test function call (see Example 2-18).

Example 2-18. getField with test function

publicstatic <B> List<B> getField(Function1<Customer,Boolean> test,

Function1<Customer,B> func) {

ArrayList<B> outList = new ArrayList<B>();

for (Customer customer : Customer.allCustomers) {

if (test.call(customer)) {

outList.add(func.call(customer));

}

}

return outList;

}

Now, at first glance, we see that with this approach we’re going to be copying and pasting a ton of anonymous functions for each function. Instead, we’ll create two variables in which we will store the Enabled and Disabled Function1 implementations.

Inside of our Customer class, we’ll create two function variables, EnabledCustomer and DisabledCustomer. This allows us to apply the DRY principle by not rewriting our Enabled and Disabled function implementations:

staticfinalpublic Function1<Customer,Boolean> EnabledCustomer =

new Function1<Customer,Boolean>()

{

public Boolean call(Customer customer) {

return customer.enabled == true;

}

};

staticfinalpublic Function1<Customer,Boolean> DisabledCustomer =

new Function1<Customer,Boolean>()

{

public Boolean call(Customer customer) {

return customer.enabled == false;

}

};

What does a call to this look like? Let’s look at the following getDisabledCustomerNames function to see that we just pass the DisabledCustomers object as the first parameter:

publicstatic List<String> getDisabledCustomerNames() {

return Customer.getField(

Customer.DisabledCustomers,

new Function1<Customer, String>() {

public String call(Customer customer) {

return customer.name;

}

}

);

}

As you can see, each of our getCustomer* methods looks a little nasty. Normally in functional programming, we wouldn’t have all of these getCustomer* methods; instead, we would call the Customer.getField method where we needed the call. In the instance where we are making multiple calls over the code base—for example, if we called getDisabledCustomerNames in a few different places—we would then create a method encapsulating that call (think DRY).

Refactoring get Functions by Using Groovy

Let’s look at an example in Groovy to see how we could implement getDisabledCustomerNames and getEnabledCustomerNames in a more functional language. Example 2-19 shows these two pieces of functionality.

Notice that we are able to use the findAll function, which allows you to filter a list based on another function, as we did with our for with the inner if structure inside getField. We then use the collect method to convert one object into another, as we did with our Function1 passed into the getField.

Example 2-19. getEnabledCustomerNames and getDisabledCustomerNames functions in Groovy

// Get all enabled customer names

allCustomers.findAll(

{ customer -> customer.enabled == true }

).collect(

{ customer -> customer.name }

)

// Get all disabled customer names

allCustomers.findAll(

{ customer -> customer.enabled == false }

).collect(

{ customer -> customer.name }

)

GROOVY SYNTAX

There are a couple of things to note about our code in Example 2-19.

§ There is no need for the keyword return. Groovy uses the last statement in a function as the return of that function.

§ An anonymous function is composed of curly braces, {}, with an arrow, ->. To the left of the arrow is the parameter list, and to the right is the body of the function.

§ No semicolons are necessary when you are writing in Groovy.

The big thing you’ll notice is that we’ve reiterated ourselves with the allCustomers.findAll(. . .).collect(. . .) call; and while we might say that this is duplicated code, it is a very minimal duplication in which we are actually being more expressive. If you remember back ingetDisabledCustomerNames, the amount of code required to get the names was much higher than in our Groovy code, and not as readable.

A function becomes “higher order” if it accepts or returns a function. Because functions are not objects in Java, it does not have the concept of a higher-order function. But, in our interface equivalency, we can see that the higher-order function is actually getField from Example 2-18because it accepts a “function.” In Example 2-19, we can see that the functions findAll and collect are both higher order because they themselves accept functions.

Why are higher-order functions so important? Think about the functions as objects: if we are able to pass functions as objects (without wrapping them in objects), we must have higher-order functions. Otherwise, what would utilize those functions as objects?

Conclusion

At this point, you should have an idea of how use first-class functions. In our examples, we made our new code functional and then went back and migrated our pre-existing code to the functional style. You should always remember that any time is a good time to make code more functional.

We took a little extra time to refactor our copy-and-paste code into a higher-order function that iterated over our list of customers. After that, we refactored the inner workings of our copy-and-paste code into simple, anonymous functions and even used a closure in case our boss ever wants to extend the functionality of the prepending email addresses.

The more we converted our copy-and-paste code using these functional concepts, the simpler our code became. It also became much easier for us to add new functionality because we no longer had to copy and paste things like our for loops or other pieces that we extracted into our higher-order function getField.

You don’t always need 10 functions to cover every possible use case in the future. Of course, if getEnabledCustomerNames were to happen 5 or 10 times, it might make sense to create the function itself and make it a call to be done such that people aren’t duplicating that code.

Many of these abstractions, such as our Function1, are already defined in libraries like Guava. For those of you who can’t switch to a language like Groovy, I would suggest looking into these types of libraries, which already have these abstractions available.

FURTHER READING

The next time you are reading a programming language book, be on the lookout for how you might be able to implement higher-order functions in that language. All languages can do some form of function passing, even C (using function pointers).