[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