Closure-Based State Explained

DZone 's Guide to

Closure-Based State Explained

Patterns, 20 Years Later: With the prevalence of libraries and tools that can peer past access controls (such as Reflection on the JVM and CLR, or the Mirrors facility in Swift), trying to encapsulate private details away from prying eyes can be increasingly difficult.

Problem

We want to preserve “information hiding” and avoid exposing details of how and where internal state is being held.

Context

Reflection libraries can bypass “private” and other access controls. This is a good thing in a number of ways, but Reflection libraries also offer opportunities to completely undo the benefit of access controls.

The language has no concept of object. In a traditional functional language, it’s actually difficult to keep state and data tied together. In fact, part of the whole point of a functional language is towrite functions that operate on data, ideally on lots of different kinds of data. In such languages, then, when seeking to keep state and operations together, we have to get a little tricky to obtain the traditionalthings that an object-oriented language provides for free.

The language offers a closure facility around function literals. Meaning, the language knows how to “close over” local variables being referenced within scope of the function’s definition, yet outside of the function definition itself. (Almost all languages developed since 2000 offer such capability, and those that didn’t have it before, such as C++, Java, and others, have already or are being modified to include it.)

Solution

Use the closure facilities of the language to hold state referenced from within the function, thus providing thefunctionality of a private field without requiring or using that language facility.

Note that there is no reason that a given system couldn’t use both Closure-based State and the traditional privatefields within a class, so as to have those fields hidden via “private” yet still accessible via Reflection (and thusto tools that make use of Reflection, a la object-relational libraries or serialization systems), yet also have certain data entirely inaccessible to Reflection systems.

Implementations

The Envoy pattern language, from which this pattern is borrowed, describe sseveral implementations as part of that pattern language.

(Additional implementations forthcoming.)

Consequences

Invisible references. The closure is an “invisible reference” from the object, and the closure, along with anyadditional variables referenced from that enclosing scope. That means that potentially the Closure-based Statedata will keep more objects alive for longer than intuition suggests, which can create potential memory pressureon the program if it grows out of hand.

Variations

Strategy implementations can hold data as fields in the Strategy object itself, which essentially provides much of the same kind of functionality as Closure-based State, without the concerns around Reflection being addressed at all.

Closure-based State can also be used at the module level for those languages which support modules as first-classconcepts, a la F# or Javascript for the same reasons. (In point of fact, many languages which support modules do so by modeling them internally as a singleton object implicitly held at the global scope and always referencedor considered “in scope”. Javascript does this, for example, and can be easily seen by iterating across the members of “this” at the top level of a script.)

Relationships

Closure-based State can fairly easily adapt to use the State pattern to adjust its internal stateand operations. Operations would be “trampolining” into functions defined in the closure, rather than on the object itself.