Closures in Logo

Java supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.

import java.util.function.Supplier;

public class Closures {

    // This method returns a Supplier<Integer>, which is similar to a function
    // that takes no arguments and returns an integer. The returned Supplier
    // closes over the variable i to form a closure.
    public static Supplier<Integer> intSeq() {
        final int[] i = {0};  // We use an array to hold a mutable int
        return () -> {
            i[0]++;
            return i[0];
        };
    }

    public static void main(String[] args) {
        // We call intSeq, assigning the result (a Supplier<Integer>)
        // to nextInt. This Supplier captures its own i value, which
        // will be updated each time we call nextInt.get().
        Supplier<Integer> nextInt = intSeq();

        // See the effect of the closure by calling nextInt.get()
        // a few times.
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());

        // To confirm that the state is unique to that
        // particular Supplier, create and test a new one.
        Supplier<Integer> newInts = intSeq();
        System.out.println(newInts.get());
    }
}

To run this program:

$ javac Closures.java
$ java Closures
1
2
3
1

In Java, we use the Supplier<Integer> interface to represent a function that takes no arguments and returns an integer. The intSeq() method returns a Supplier<Integer> that encapsulates the incrementing behavior.

The closure is created using a lambda expression () -> { ... }, which captures the i array. We use an array to hold a mutable integer because local variables captured by lambda expressions must be effectively final.

The main method demonstrates how the closure maintains its own state, with each Supplier instance having its own independent counter.