[e-lang] Consequences of transactional E? (was: Non-local Exits vs Defensive Consistency)
Kevin Reid
kpreid at mac.com
Mon Jan 29 09:55:04 CST 2007
David Hopwood wrote:
> This is a summary of a series of articles proposing to add support
> for lightweight transactions to E, Oz-E, and other security-
> oriented event-loop languages. (I wrote it originally as a single
> article, but it got ridiculously long.)
> ...
> Non-local exits, with the semantics used in most languages
> including E, make it unreasonably difficult to ensure defensive
> consistency or correctness.
So. What are the consequences if we move E to this model? I've listed
some below.
1.
As David Hopwood already pointed out:
> It is, however, necessary to use a *pure* event-loop model for this
> to work. E currently has some synchronous I/O facilities, which
> would have to be reviewed and possibly removed.
I would not mind this; to a certain degree E 'should have' been this
way already.
2.
The return statement would likely need to be eliminated, because it
looks like 'normal' exiting but is actually a nonlocal exit.
The easy-return syntactic mode (currently preferred) would have to be
replaced with something else. In easy-return,
to foo() :any {
a()
b()
return c
}
expands to
method foo() :any {
escape __return {
a()
b()
__return(c)
}
}
, but this would have the undesired consequence of discarding side
effects.
Similarly, some programming with nonlocal exits would need to be
revised; anything which uses explicit ejectors in the same style as
easy-return. Hopefully, most such cases can be rewritten to have
effects after the exits, e.g.
escape e {
...(fn { foo := false; e() })
}
becomes:
escape e {
...(e)
} catch _ {
foo := false
}
3. It is possible to have values generated by a world that no longer
exists; this prevents programs from ensuring consistency between
mutable state and existant objects. For example:
var i := 0
def makeUnique() {
def serial := i += 1
# Ignoring the 'return' issue for now...
return def object {
to __printOn(out) {
out.print("<", serial, ">")
}
}
}
def bogus := escape e { e(makeUnique()) }
In current E, the products of this maker can be relied on to have
unique serial numbers. In transactional-E, 'bogus' will outlive the
transaction of its creation, resulting in the next creations having a
non-unique serial number.
I can think of some ways of avoiding this problem:
- Don't assign serial numbers (in this example) until one is going
to use them, and keep them as local state in that use.
- Ensure that makeUnique is only called in a separate turn, i.e. a
separate top-level transaction. This will be reliable as long as that
transaction cannot fail internally and yet return the object, which
should be reasonably easy.
- Allow only Selfless objects to be carried by nonlocal exits. I
believe this is too restrictive, as otherwise exception objects
cannot carry information useful for debugging without expensive
printing at throw time, when it is not known if the information will
ever be looked at.
--
Kevin Reid <http://homepage.mac.com/kpreid/>
More information about the e-lang
mailing list