Nothing New in RDP

Access to state resources is a common requirement for many applications. Many tasks require fresh state that is not shared with any other service or behavior. In many programming models, one could achieve this by declaring a variable or a `new` object.

With Reactive Demand Programming (RDP) one cannot ask for `new` objects. There are many arguments leading to this conclusion. For example, RDP’s demands have some positive duration, and it is unclear how a request for a `new` object could possibly have a duration (when does the request become old?). But I prefer arguing from a couple of RDP’s properties:

  • spatial idempotence: two identical requests at the same time must return two identical values.
  • no looking back: cannot use old references to dynamic behaviors

Between these properties, overlapping demands for `new` objects would all return the same object, and demands would certainly overlap because one cannot store the answer if it contains dynamic behaviors.

More generally, RDP cannot directly request `new` identity, whether this be in the form of demand monitors, GUIDs, random numbers, or service instances.

[edit] There are indirect mechanisms to model `new` via a shared state resource. A reactive term rewrite model, one could atomically claim a range of surrogate IDs. However, to do this would require a storable seed identity (e.g. a GUID) with which to mark the claim, otherwise it would be unclear who owns which identifiers.

State Directories

So how do I obtain fresh resources in an RDP model?

The short answer: demand state with an identity that I know to be unique. I.e. the unique identity is part of the request, not part of the answer.

In practice, the runtime provides each application a fresh state volume – like an abstract chroot’d filesystem, but with much better support for language abstractions (types, signals, lazy evaluation, etc.). A developer can then guarantee uniqueness by securely partioning this volume into directories, and sharing the directories. There is never a path from child to parent, so this is effectively relative paths ‘all the way down’ until the per-project or IDE layer.

A simple Haskell model of a directory might be:

data Directory p e = Directory 
  { dpath :: p -> (e, Directory p e)

In a typical case, `p` might simply be `String`, and `e` might refer to any fresh state resources or model (or even a demand monitor).

Essentially this is an infinite function. Unfortunately, there are a few troubles with this model:

  1. If creating an `e` is effectful (e.g. to create a new IORef) then we’d either need unsafePerformIO to obtain new paths on demand, or to perform a potentially infinite set of operations up front.
  2. It is unclear how to achieve a ‘fresh’ directory, or even what that means, so it seems the runtime has special privileges to create a fresh directory. Modeling reflective towers – a stack of interpreters within interpreters or runtimes within runtimes – would be awkward and ad-hoc.

To aide with these difficulties, I remodel in RDP (so I have RDP’s effects model, which is very function-like) and add a capability to reset a whole volume. The result looks closer to:

data Directory (~>) s p e = Directory 
  { dpath :: s p ~> (s () :|: (e :&: s (Directory (~>) s p e)))
  , dzero :: s () ~> s ()

The `dzero` operation temporarily disables access to the volume (every path returns `s ()`) and when dzero is released the directory (and recursively all subdirectories) are provided in a fresh state. What fresh means will depend on the type `e`. I’m assuming here that the `e` type is itself a proper RDP type (a signal or asynchronous sum or product thereof).

Advantages and Disadvantages

There are many advantages to the state directories approach:

  • auditing and extension: it is preferable to share state explicitly by capability, rather than by directory and name. This is a common pattern for cooperative state models – e.g. databases, tuple spaces, or a blackboard system. However, when the sharing of state was not preconceived, use of directories allows peeking into the state used by a sub-module for varied purposes such as auditing, reflection, and extension.
  • orthogonal persistence: identity for state will tend to be stable across disruption, and the state is modeled as external to the application anyway. Orthogonal persistence-by-default is natural, while still allowing developers to model resets if they wish.
  • live upgrade: identity for state resources will, if explicit in source, tend to be stable even across updates to the program and live programming, much like filesystems and databases. It is feasible to support many updates without reset, so long as they don’t require a change to the data structures.
  • referential transparency: if we make the same demand for a resource, we retrieve the same resource. This property is lost if we support `new`, but remains compatible with directories.
  • secure access to state: if you want a subprogram to be stateless, simply don’t share a directory.

There are also a few disadvantages:

  • specifying paths and partitioning directories is noticeably more verbose than requesting `new` elements. I believe it can be kept unobtrusive, especially with a little syntactic sugar or integration with the module/import system. Most of the advantages are only valid if the names are explicit in code and thus stable, so we should be paying for explicit paths.
  • the model is slightly less flexible. Patterns involving an arbitrary number of volatile objects are difficult to express – though, if you can distinguish them on content, you could use a tuple space and create a record per object. Fortunately, RDP avoids many conditions that normally call for volatile state.

Developers will need to learn new idioms, of course, but that goes without saying on a transition to RDP.

This entry was posted in Reactive Demand Programming, State. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s