ERights Home elib / concurrency / eio 
Back to: EIO Design Goals No Next Sibling

Elements from an InStream

Though InStream has many methods, it has only a few primitives. The primitive used for obtaining elements from the stream is:

public Object obtain(int atLeast,
                     int atMost,
                     String sched,
                     String proceed,
                     String report)
              throws UnavailableException,
Most of the other InStream methods are just convenient repackagings of this primitive. This primitive and all its packagings are collectively refered to as input operations.

The values of four of these parameters -- atLeast, sched, proceed, and report -- form a four-dimensional 2*2*3*2 taxonomy of input operations, visualized in the following two tables.

proceed * report

reading skipping
peeking checking

The main taxonomy is formed by the proceed and report parameters. Each has only two possible values, shown as the row and column labels, respectively.

(At first I defined these as boolean parameters, but looking at "..,true,false)" in an argument list is much less clear than looking at "..,ADVANCE,STATUS)".)

The proceed parameter says whether

  • ADVANCE - The stream should be advanced past the obtained elements, relieving backpressure and allowing further elements to flow downstream.

  • QUERY - The input operation should leave the stream unaffected so that these elements may be re-obtained.

The report parameter says what the operation should report as its result:

  • ELEMENTS - A list of the elements obtained. If at end of stream, an empty list is returned rather than null.

  • STATUS - The termination status of the stream after these elements have been obtained. When asked to report STATUS, the obtained elements are ignored.

Crossing these, we get:

  • reading operations - that report the elements obtained, and advance the stream past these elements, thereby consuming these elements from the stream. (A more suggestive name would have been "taking" (and "take" for the corresponding method names), but "reading" and "read" is the conventional name for these.)

  • skipping operations - That advance the stream past a certain number of elements without reporting them, thereby consuming them without making them accessible.

  • peeking operations - That report the next elements from the stream without consuming them.

  • checking operations - For checking what the stream's termination status will be after a certain number of elements have been consumed.

The row and column labels on the next table show our two remaining dimensions. In order to show the complete taxonomy, in each of the resulting 3*2 cells we show the above 2*2 table, giving us a taxonomy of 24 possible input operations. Although all are well defined, only a few will normally be used. For these, we have defined convenience methods that are defined by their expansion to obtain/5.

sched * atLeast

in 0..ALL
atLeast == ALL

The sched parameter says how the operation should be scheduled:

  • NOW - The operation is performed immediately, whether or not sufficient elements are ready.

    If a sufficient number of elements cannot be obtained immediately, then an UnavailableException or other IOException is thrown. If an UnavailableException is thrown, then nothing was consumed and no side-effects should have happened. If another IOException is thrown, then any number up to atMost may have been consumed.

  • WAIT - Warning: may block the vat and cause deadlock.

    If the operation can succeed immediately, it is performed immediately. Else, if insufficient elements are currently ready, and if this InStream supports waiting, then the calling vat/runner/thread is blocked until this operation can immediately complete. The wrappers of streams support waiting.

    This should normally only be used when

    • The programmer knows the source to be prompt even though the underlying stream doesn't.

    • This vat (and its runner) exists for the purpose of building one virtual device from some underlying non-prompt stream, as with a one-top-level-expr-at-a-time parser parsing an InStream of characters.

  • LATER - Registers a claim for the next atLeast..atMost elements, and returns a promise for them.

    When these characters become ready, the claim will be satisfied and the promise will be resolved.

An input operation must obtain a sufficient number of elements. The atLeast and atMost parameters express bounds on the number of elements that are considered sufficient. Both atLeast and atMost may be ALL (ie, Integer.MAX_VALUE), or may be any non-negative integer between 0 and ALL (a quantity). When atLeast is

  • ALL - then a sufficient number of elements means all the remaining elements that will ever appear on the stream, from the next element until stream termination.

  • a quantity - then a sufficient number means at least this many, or all the remaining elements on the stream, whichever comes first.

atMost must be >= atLeast. When atLeast is ALL atMost must also be ALL. A sufficient number never exceeds atMost.

Crossing all these dimensions, we get the full taxonomy, each element of which is represented by a cell in the above table. The labels are the convenience methods we've provided for normal operation, defined by the following expansions:

Convenience Expansion

If a sufficient number of elements are ready NOW, obtain atLeast that many , but not more than atMost, elements, ADVANCE the stream past them, and return a list of those ELEMENTS.

If a sufficient number aren't ready NOW, complain and read nothing.



read as many elements as are ready NOW, but not more than num.



read as many elements as are ready NOW.


switch (read(1,1)) {
    match []  { null }
    match [x] { x }

If the stream is terminated, return null. Else return the next element. For streams than may contain null elements, readOptOne should probably be avoided, or the caller must be careful to deal with the resulting ambiguity -- the two reasons why a null might be returned.

If the stream isn't yet known to be terminated, and the next element is not yet ready, then complain and return nothing.



read ALL the remaining elements NOW, which must therefore all be ready now.



obtain num elements (or all remaining elements, whichever comes first) NOW, as a QUERY (does not ADVANCE the stream), and return a list of these ELEMENTS.



Claim the next sufficient number of elements (according to atLeast..atMost), to be obtained at a LATER time, once they are ready, and ADVANCE the stream past this claim. Return a vow that will resolve to a list of these ELEMENTS.



ADVANCE the stream past the next num elements (or to stream termination, whichever comes first), and return a vow for the stream's termination STATUS, to be resolved LATER after these elements have been skipped.



Claim ALL the remaining elements of the stream, and return a vow that will resolve to a list of these elements. Any further input operations apply at the stream's termination.



A QUERY that returns a vow that resolves LATER, when num elements have become ready (or all remaining elements have become ready, whichever happens first). The returned vow then resolves to the stream's expected termination status after these elements have been consumed.


Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home elib / concurrency / eio 
Back to: EIO Design Goals No Next Sibling
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign