[e-lang] What is defensive consistency?

Dean Tribble tribble at e-dean.com
Fri Nov 2 21:47:44 EDT 2007


On 11/2/07, David Wagner <daw at cs.berkeley.edu> wrote:
> Dean Tribble writes:
> >How's this for a definition: A client is  a holder of the capability with an
> >independent interest from the holders of the capability.
> ...
> Unfortunately, this feels a little bit like an "aspirational" goal.
> It describes what we should strive to achieve, but what does it mean
> for the programmer who has to write the defensively-consistent code?
> If a server is invoked twice, how does it tell whether those callers
> have independent interests (or even be the same client invoking the
> server twice)?  In an object capability language, the object being
> invoked is not passed any information about the identity or interests
> of the caller.

Generally, the object should be defensively consistent regardless of
the source of the incoming requests.  Then the issue is irrelevant.
For many abstractions, that means having different objects per
different client (e.g., every caller that opens a file form a
FileSystem gets a different FileStream).  That's OK since it follows
Cap Design Rule #1: represent all distinctions in authority with
different objects.

> Perhaps the answer is that the programmer of the server object needs
> to decide and document what promises the server will make, regarding
> when it will treat two method calls as potentially made by clients with
> independent interests vs which pairs of methods it will presume are made
> by a single client (or by a pair of clients with the same interest).
> That then shifts the burden onto the client to follow the documented
> protocol.

In practice, this is rarely an issue, since you are in one of the
following cases:

- the abstraction can be made client-independent
- the object needs to be split off a different object per client
- the abstraction doesn't conceptually provide significant failure
isolation (e.g., hashtable), so multiple clients rely on each other.

That provides an interesting perspective on "facets": two capabilities
are facets of the same larger composite if they rely on each other.

> In the case of a single object that is intended to be defensively
> consistent, I can think of three kinds of defensive consistency:

This kind of characterization will be valuable if it works out.  It
may be too mechanical of an interpretation, however. It's a little
like asking whether a "coherent concept" is best expressed at the
paragraph level or the sentence level; they are different levels of
abstraction.

"When we say that a program P is correct, we normally mean that we
have a specification
in mind (whether written down or not), and that P behaves according to
that specification."  "Specification" is not typically at the method
level.  If the API in the Logger example took a mutable object (in
order to avoid allocations for lightweight logging), then the
specification might include:

- the Logger MUST record log records for each client in the order they
are provided by that client (possibly interleaved with records from
other clients)

- the Logger MUST keep individual records contiguous (interleaving is
at the log record boundary)

- the Logger MAY discard, truncate, reorder, or misrepresent log
records that violate client requirements (below)

- clients SHOULD NOT concurrently update log arguments during a call
from them to the logger

- clients SHOULD NOT provide records larger than X
etc.

Defensive consistency would drive additional requirements; for
example, bad log records MUST NOT prevent logging of other records and
log records should never be exposed to clients through this interface.

> a) Every method call stands on its own.

In the above example, each log request stands on its own, but the
interesting guarantee of preserving order spans requests.

> b) All method calls to a single instance of the server are assumed to
> come from clients with a common interest.

That's a fine way to achieve or simplify some analysis of defensive
consistency, but then you must also verify that the assumption is true
(e.g., by construction).

> Thus, if the server is ever
> invoked by a caller that fails to establish the documented preconditions,

In the above case, documented preconditions may not be verifiable,
perhaps because they are a bad idea (e.g., mutable log arguments) or
perhaps because they are simply too complicated to prove.

> c) The server object might build some special method of authenticating its clients.

The CallbackSequencer example used that pattern. Note that EQ is very
handy for this, assuming you have some relevant object that is
per-client.

> And of course the server would need to document which of these three
> types of defensive consistency it provides, so that clients can know
> what they can rely upon and so they can know how to use the server safely.

My impression is that these often exist together and which applies is
inherent in the documentation of the contract.

> Those three cases seems like just about it, if we're talking about a
> single object.  Is that all there is to it?

Not quite, since it didn't deal with implied things like order of
invocation (as in the logger case).

> I wonder if perhaps my intuition has been poorly served by focusing on
> the case of building a defensively consistent object.  Perhaps I should
> be thinking about a defensively consistent subsystem, which might be
> composed of multiple objects and which might expose multiple facets
> to the outside world.

This is part of what prompted my thoughts above, so I agree :)

> Then perhaps we can distinguish method calls
> according to which facet they are invoked upon, enabling a richer set of
> options for what type of defensive consistency the subsystem provides.
> Does that sound right?  Is that a more typical case?

Yes it does.
>
> Thanks again for your comments, Dean.  They are very helpful.

I'm delighted.


More information about the e-lang mailing list