About me

Michael L Perry

Improving Enterprises

Principal Consultant

@michaellperry

User login

Closure

When I say "closure", I'm talking about two things. First, there's the language feature. Second, there's the concept. Either way, it is fundamental to proving software.

Language feature
As a language feature, closure is the ability to bring variables into scope and encapsulate them within a function. Different languages support this feature in different ways. In C#, it is supported in lambdas and anonymous delegates.

public Order GetOrder(string orderId)
{
    return GetOrderRepository()
        .GetSatisfying(o => o.OrderId == orderId)
        .Query()
        .FirstOrDefault();
}

The parameter orderId is available within the lambda, even though the lambda executes outside of the scope of this method.

As of Java 6, closure is supported only by anonymous inner classes. It is slated for becoming a first-class language feature in Java 7.

public Order getOrder(final string orderId) {
    return Query
        .from(getOrders())
        .where(new Predicate<Order>() {
            public boolean where(Order row) {
                return row.getOrderId() == orderId;
            }
        })
        .selectOne();
}

Again, the orderId parameter is available within the anonymous inner class. It will be set to the the correct value even though Predicate.where() is called by code not located in the method. In Java, the variables to be enclosed must be marked as "final" to ensure that they are not changed after the closure is created.

Factory methods
As a concept, closure can be used in several places. It doesn't take an explicit language feature to take advantage of the concept. In fact, the Factory Method pattern is often used to perform closure.

A factory method constructs an object, but hides its class. In doing so, it usually takes parameters that are injected into the new object. These parameters obey the laws of closure.

public IOrderService
    CreateOrderService(
        ITransaction transaction)
{
    return new
        OrderService(
            transaction,
            _accountsServiceProvider,
            _catalogServiceProvider);
}

The transaction parameter is enclosed within the object. An object, just like a lambda, is a packet of behavior that can be executed later. The value of transaction is already set at the time that the behavior is executed.

Constructors
Notice that there are two other parameters passed into the OrderService. These two are set in the constructor of the factory itself.

private IServiceProvider<IAccountsService> _accountsServiceProvider;
private IServiceProvider<ICatalogService> _catalogServiceProvider;

public OrderServiceFactory(
    IServiceProvider<IAccountsService> accountsServiceProvider,
    IServiceProvider<ICatalogService> catalogServiceProvider)
{
    _accountsServiceProvider = accountsServiceProvider;
    _catalogServiceProvider = catalogServiceProvider;
}

The factory encloses some parameters and forwards them on to all of the objects it creates. In this way, closure can be nested.

Just like the "final" parameter in the Java example, we don't want these values changing. For the same reason that Java requires the "final" keyword for closure, fields initialized by the constructor should be considered immutable.

Closure is a useful mechanism for writing provable software. Whether we use it as a language feature or simply as a pattern, it allows us to bring values into a function or object. We can then prove interesting things about those values, as we will see in coming posts.