ref_send API 1.16
defensive programming in Java

org.ref_send.promise.eventual
Class Eventual

java.lang.Object
  extended by org.joe_e.Struct
      extended by org.ref_send.promise.eventual.Eventual
All Implemented Interfaces:
java.io.Serializable, Selfless

public final class Eventual
extends Struct
implements java.io.Serializable

The eventual operator.

This class decorates an event loop with methods implementing the core eventual control flow statements needed for defensive programming. The primary aim of these new control flow statements is preventing plan interference.

The implementation of a public method can be thought of as a plan in which an object makes a series of state changes based on a list of invocation arguments and the object's own current state. As part of executing this plan, the object may need to notify other objects of the changes in progress. These other objects may have their own plans to execute, based on this notification. Plan interference occurs when execution of these other plans interferes with execution of the original plan.

Plan interference

Interleaving plan execution is vulnerable to many kinds of interference. Each kind of interference is explained below, using the following example code:

 public final class
 Account {

  private int balance;
  private final ArrayList<Observer> observers;

  Account(final int initial) {
      balance = initial;
      observers = new ArrayList<Observer>();
  }

  public void
  observe(final Observer observer) throws NullPointerException {
      if (null == observer) {
          throw new NullPointerException();
      }
      observers.add(observer);
  }

  public int
  getBalance() { return balance; }

  public void
  setBalance(final int newBalance) {
      balance = newBalance;
      for (final Observer observer : observers) {
          observer.currentBalance(newBalance);
      }
  }
 }
 

Unanticipated termination

A method can terminate execution of its plan by throwing an exception. The plan may be terminated because it would violate one of the object's invariants or because the request is malformed. Unfortunately, throwing an exception may terminate not just the current plan, but also any other currently executing plans. For example, if one of the observers throws a RuntimeException from its currentBalance() implementation, the remaining observers are not notified of the new account balance. These other observers may then continue operating using stale data about the account balance.

Nested execution

When a method implementation invokes a method on another object, it temporarily suspends progress on its own plan to let the called method execute its plan. When the called method returns, the calling method resumes its own plan where it left off. Unfortunately, the called method may have changed the application state in such a way that resuming the original plan no longer makes sense. For example, if one of the observers invokes setBalance() in its currentBalance() implementation, the remaining observers will first be notified of the balance after the update, and then be notified of the balance before the update. Again, these other observers may then continue operating using stale data about the account balance.

Interrupted transition

A called method may also initiate an unanticipated state transition in the calling object, while the current transition is still incomplete. For example, in the default state, an Account is always ready to accept a new observer; however, this constraint is temporarily not met when the observer list is being iterated over. An observer could catch the Account in this transitional state by invoking observe() in its currentBalance() implementation. As a result, a ConcurrentModificationException will be thrown when iteration over the observer list resumes. Again, this exception prevents notification of the remaining observers.

Plan isolation

The above plan interference problems are only possible because execution of one plan is interleaved with execution of another. Interleaving plan execution can be prevented by scheduling other plans for future execution, instead of allowing them to preempt execution of the current plan. This class provides control flow statements for scheduling future execution and receiving its results.

Naming convention

Since the control flow statements defined by this class schedule future execution, instead of immediate execution, they behave differently from the native control flow constructs in the Java language. To make the difference between eventual and immediate execution readily recognized by programmers when scanning code, some naming conventions are proposed. By convention, an instance of Eventual is held in a variable named "_". Additional ways of marking eventual operations with the '_' character are specified in the documentation for the methods defined by this class. All of these conventions make eventual control flow statements distinguishable by the character sequence "_.". Example uses are also shown in the method documentation for this class. The '_' character should only be used to identify eventual operations so that a programmer can readily identify operations that are expected to be eventual by looking for the _. pseudo-operator.

See Also:
Section 13.1 "Sequential Interleaving Hazards" of "Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control", Serialized Form

Field Summary
 Loop<Task> enqueue
          Schedules a task for execution in a future turn.
 Log log
          debugging output
 
Constructor Summary
Eventual(Token deferred, Loop<Task> enqueue, Log log)
          Constructs an instance.
 
Method Summary
<T> T
_(T reference)
          Ensures a reference is an eventual reference.
<T extends java.io.Serializable>
void
_(T x)
          Causes a compile error for code that attempts to create an eventual reference of a concrete type.
<R extends java.io.Serializable>
void
cast(java.lang.Class<R> type, Volatile<?> promise)
          Causes a compile error for code that attempts to create an eventual reference of a concrete type.
<T> T
cast(java.lang.Class type, Volatile<T> promise)
          Creates an eventual reference.
static
<A,B> Do<A,java.lang.Void>
compose(Do<A,B> first, Resolver<B> second)
          Constructs a call return block.
<T> Channel<T>
defer()
          Creates a promise in the deferred state.
static
<T> T
near(T reference)
          Gets the corresponding immediate reference.
static
<T> T
near(Volatile<T> promise)
          Gets the corresponding immediate reference.
static
<T> Volatile<T>
promised(T reference)
          Gets the corresponding promise.
<T,R> R
when(T reference, Do<T,R> observer)
          Registers an observer on an eventual reference.
<T,R extends java.io.Serializable>
void
when(T reference, Do<T,R> observer)
          Causes a compile error for code that attempts to return a concrete type from a when block.
<T,R> R
when(Volatile<T> promise, Do<T,R> observer)
          Registers an observer on a promise.
<T,R extends java.io.Serializable>
void
when(Volatile<T> promise, Do<T,R> observer)
          Causes a compile error for code that attempts to return a concrete type from a when block.
 
Methods inherited from class org.joe_e.Struct
equals, hashCode
 
Methods inherited from class java.lang.Object
getClass, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

enqueue

public final Loop<Task> enqueue
Schedules a task for execution in a future turn.

The implementation preserves the First In First Out ordering of tasks, meaning the tasks will be executed in the same order as they were enqueued.


log

public final Log log
debugging output

Constructor Detail

Eventual

public Eventual(Token deferred,
                Loop<Task> enqueue,
                Log log)
Constructs an instance.

Parameters:
deferred - Deferred permission
enqueue - enqueue
log - log
Method Detail

when

public <T,R> R when(Volatile<T> promise,
                    Do<T,R> observer)
Registers an observer on a promise.

The observer will be notified of the promise's state at most once, in a future event loop turn. If there is no referent, the observer's reject method will be called with the reason; otherwise, the fulfill method will be called with either an immediate reference for a local referent, or an eventual reference for a remote referent. For example:

 import static org.ref_send.promise.Resolved.ref;
 …
 final Promise<Account> mine = …
 final Promise<Integer> balance =
     _.when(mine, new Do<Account,Promise<Integer>>() {
         public Promise<Integer>
         fulfill(final Account x) { return ref(x.getBalance()); }
     });
 

A null promise argument is treated like an instance of Rejected with a reason of NullPointerException.

Multiple observers registered on the same promise will be notified in the same order as they were registered.

This method will not throw an Exception. Neither the promise, nor the observer, argument will be given the opportunity to execute in the current event loop turn.

Type Parameters:
T - referent type
R - observer's return type, MUST be Void, an allowed proxy type, or assignable from Promise
Parameters:
promise - observed promise
observer - observer, MUST NOT be null
Returns:
promise, or eventual reference, for the observer's return, or null if the observer's return type is Void
Throws:
java.lang.Error - invalid observer argument

compose

public static <A,B> Do<A,java.lang.Void> compose(Do<A,B> first,
                                                 Resolver<B> second)
Constructs a call return block.

Parameters:
first - code block to execute
second - code block's return resolver

defer

public <T> Channel<T> defer()
Creates a promise in the deferred state.

The return from this method is a ( promise, resolver ) pair. The promise is initially in the deferred state and can only be resolved by the resolver once. If the promise is fulfilled, the promise will forever refer to the provided referent. If the promise, is rejected, the promise will forever be in the rejected state, with the provided reason. If the promise is resolved, the promise will forever be in the same state as the provided promise. After this initial state transition, all subsequent invocations of either fulfill, reject or resolve are silently ignored. Any observer registered on the promise will only be notified after the promise is resolved.

Type Parameters:
T - referent type
Returns:
( promise, resolver )

cast

public <T> T cast(java.lang.Class type,
                  Volatile<T> promise)
Creates an eventual reference.

An eventual reference queues invocations, instead of processing them immediately. Each queued invocation will be processed, in order, in a future event loop turn.

For example,

  // Register an observer now, even though we don't know what we plan
  // to do with the notifications.
  final Channel<Observer> x = _.defer();
  account.observe(_.cast(Observer.class, x.promise));
  …
  // A log output has been determined, so fulfill the observer promise.
  final Observer log = …
  x.resolver.fulfill(log);   // Logs all past, and future, notifications.
 

If this method returns successfully, the returned eventual reference will not throw an Exception on invocation of any of the methods defined by its type, provided the invoked method's return type is either void, an allowed proxy type or assignable from Promise. Invocations on the eventual reference will not give the promise, nor any of the invocation arguments, an opportunity to execute in the current event loop turn.

Invocations of methods defined by Object are not queued, and so can cause plan interference, or throw an exception.

This method will not throw an Exception. The promise argument will not be given the opportunity to execute in the current event loop turn.

Type Parameters:
T - referent type to implement
Parameters:
type - referent type to implement, MUST be an allowed proxy type
promise - promise for the referent
Returns:
corresponding eventual reference

_

public <T> T _(T reference)
Ensures a reference is an eventual reference.

Use this method to vet received arguments. For example:

 import static org.joe_e.ConstArray.array;

 public final class
 Account {

     private final Eventual _;
     private int balance;
     private ConstArray<Observer> observer_s;

     public
     Account(final Eventual _, final int initial) {
         this._ = _;
         balance = initial;
         observer_s = array();
     }

     public void
     observe(final Observer observer) throws NullPointerException {
         // Vet the received arguments.
         final Observer observer_ = _._(observer);

         // Use the vetted arguments.
         observer_s = observer_s.with(observer_);
     }

     public int
     getBalance() { return balance; }

     public void
     setBalance(final int newBalance) {
          balance = newBalance;
          for (final Observer observer_ : observer_s) {
              // Schedule future execution of notification.
              observer_.currentBalance(newBalance);
          }
     }
 }
 

By convention, the return from this method, as well as from cast, is held in a variable whose name is suffixed with an '_' character. The main part of the variable name should use Java's camelCaseConvention. A list of eventual references is suffixed with "_s". This naming convention creates the appearance of a new operator in the Java language, the eventual operator: "_.".

This method will not throw an Exception. The reference argument will not be given the opportunity to execute in the current event loop turn.

Type Parameters:
T - referent type, MUST be an allowed proxy type
Parameters:
reference - immediate or eventual reference, MUST be non-null
Returns:
corresponding eventual reference
Throws:
java.lang.Error - null reference or T not an allowed proxy type

when

public <T,R> R when(T reference,
                    Do<T,R> observer)
Registers an observer on an eventual reference.

The implementation behavior is the same as that documented for the promise based when statement.

Type Parameters:
T - referent type
R - observer's return type
Parameters:
reference - observed reference
observer - observer, MUST NOT be null
Returns:
promise, or eventual reference, for the observer's return, or null if the observer's return type is Void

near

public static <T> T near(T reference)
              throws java.lang.ClassCastException
Gets the corresponding immediate reference.

This method is the inverse of _; it gets the corresponding immediate reference for a given eventual reference.

Type Parameters:
T - referent type
Parameters:
reference - possibly eventual reference for a local referent
Returns:
corresponding immediate reference
Throws:
java.lang.ClassCastException - no corresponding immediate reference

near

public static <T> T near(Volatile<T> promise)
              throws java.lang.ClassCastException
Gets the corresponding immediate reference.

The implementation behavior is the same as that documented for the reference based near guard.

Type Parameters:
T - referent type
Parameters:
promise - promise for a local referent
Returns:
corresponding immediate reference
Throws:
java.lang.ClassCastException - no corresponding immediate reference

promised

public static <T> Volatile<T> promised(T reference)
Gets the corresponding promise.

This method is the inverse of cast; it gets the corresponding promise for a given reference.

This method will not throw an Exception. The reference argument will not be given the opportunity to execute.

Type Parameters:
T - referent type
Parameters:
reference - immediate or eventual reference
Returns:
corresponding promise

_

public <T extends java.io.Serializable> void _(T x)
       throws java.lang.Exception
Causes a compile error for code that attempts to create an eventual reference of a concrete type.

If you encounter a compile error because your code is linking to this method, insert an explicit cast to the allowed proxy type. For example,

_._(this).run();

becomes:

_._((Runnable)this).run();

Parameters:
x - ignored
Throws:
java.lang.Error - always thrown
java.lang.Exception

cast

public <R extends java.io.Serializable> void cast(java.lang.Class<R> type,
                                                  Volatile<?> promise)
          throws java.lang.Exception
Causes a compile error for code that attempts to create an eventual reference of a concrete type.

If you encounter a compile error because your code is linking to this method, replace the specified concrete type with an allowed proxy type. For example,

final Logger o_ = _.cast(Logger.class, op);

becomes:

final Observer o_ = _.cast(Observer.class, op);

Type Parameters:
R - referent type to implement
Parameters:
type - ignored
promise - ignored
Throws:
java.lang.Error - always thrown
java.lang.Exception

when

public <T,R extends java.io.Serializable> void when(Volatile<T> promise,
                                                    Do<T,R> observer)
          throws java.lang.Exception
Causes a compile error for code that attempts to return a concrete type from a when block.

If you encounter a compile error because your code is linking to this method, change your when block return type to a promise. For example,

 final Promise<Account> pa = …
 final Integer balance = _.when(pa, new Do<Account,Integer>() {
     public Integer
     fulfill(final Account a) { return a.getBalance(); }
 });
 

becomes:

 final Promise<Account> pa = …
 final Promise<Integer> balance =
  _.when(pa, new Do<Account,Promise<Integer>>() {
     public Promise<Integer>
     fulfill(final Account a) { return ref(a.getBalance()); }
 });
 

Parameters:
promise - ignored
observer - ignored
Throws:
java.lang.Error - always thrown
java.lang.Exception

when

public <T,R extends java.io.Serializable> void when(T reference,
                                                    Do<T,R> observer)
          throws java.lang.Exception
Causes a compile error for code that attempts to return a concrete type from a when block.

If you encounter a compile error because your code is linking to this method, change your when block return type to a promise. For example,

 final Account a = …
 final Observer o_ = …
 final Integer initial = _.when(o_, new Do<Observer,Integer>() {
     public Integer
     fulfill(final Observer o) { return a.getBalance(); }
 });
 

becomes:

 final Account a = …
 final Observer o_ = …
 final Promise<Integer> initial =
  _.when(o_, new Do<Observer,Promise<Integer>>() {
     public Promise<Integer>
     fulfill(final Observer o) { return ref(a.getBalance()); }
 });
 

Parameters:
reference - ignored
observer - ignored
Throws:
java.lang.Error - always thrown
java.lang.Exception

ref_send API 1.16
defensive programming in Java

Submit a bug or feature, or get help

Copyright 1998-2007 Waterken Inc. under the terms of the MIT X license.