[E-Lang] pending revision of E in a Walnut

Mark S. Miller markm@caplet.com
Tue, 21 Aug 2001 13:32:57 -0700


At 11:10 AM Tuesday 8/21/01, Marc Stiegler wrote:
>I am not all the way through Alan's comments, but one proposal for an upward
>compatible enhancement to the language caught my attention. Could/should the
>when-catch construct include a "finally" clause like the try-catch? Alan
>noted that one of my examples would be simpler if we had such a beast. If it
>is falling-off-a-log easy, I think it is a good idea.

It would certainly be trivial to implement.  It also seems like a good idea 
to me.  Could you post the example and Alan's comments?

This reminds me of another idea for changing the semantics of the 
when-catch.  Right now, in 

    when (xVow) -> done(x) {
        # x in scope
        doSomething(x)
    } catch prob {
        # x not in scope.  prob in scope
        handle(prob)
    }

the catch-clause is invoked only if xVow resolves to a broken reference 
(becomes broken).  If doSomething(x) throws a problem, this does not 
currently cause the catch-clause to run, and the thrown problem goes 
nowhere.  (Normally nowhere, since it's in response to a sendOnly, in which 
case it will normally still be logged into the etrace file for debugging 
purposes.)  We can think of the catch clause as applying to the 
"when (...) ->" section of the when-catch.

Unlike Alan's, the following proposal is not actually upwards compatible, but 
I think it's practically upwards compatible enough for current purposes, and 
it's both more intuitive and more useful.

Proposal: If doSomething(x) does throw a problem, catch this problem in the 
catch clause as well -- binding prob and calling handler.  Since the "x" 
parameter of "done(x)" can be any pattern, the catch clause can catch its 
failure to match as well.

We would then think of the catch clause as applying to the 
"when (...} catch" section of the when-catch, much as try-catch applies to 
the "try {...} catch" section.  This is more intuitive, being more like 
try-catch, and more useful -- when there's some sensible excuse for 
reporting a problem to a particular party, it's almost always better to do 
so than to drop it on the floor.  The etrace log is a place-to-report of 
last resort, and exists only in the implementation, not in the computational 
model.


The current expansion of the above is:

    Ref whenResolved(xVow, def done(temp) {
        if (Ref isBroken(temp)) {
            def prob := Ref optProblem(temp)
            handle(prob)
        } else {
            def x := temp
            doSomething(x)
        }
    })

An expansion that would realize both proposals would expand

    when (xVow) -> done(x) {
        # x in scope
        doSomething(x)
    } catch prob {
        # x not in scope.  prob in scope
        handle(prob)
    } finally {
        # neither x nor prob in scope
        doLast()
    }

to

    Ref whenResolved(xVow, def done(temp) {
        try {
            def tempProb := Ref optProblem(temp)
            if (Ref isBroken(temp)) {
                throw(Ref optProblem(temp))
            }
            def x := temp
            doSomething(x)
        } catch prob {
            handle(prob)
        } finally {
            doLast()
        }
    })

By turning an incoming broken reference back into exceptional control flow, 
the rest of the expansion can just use try-catch-finally in the familiar way.

OTOH, in some formal way this seems less clean, as the previous when-catch 
was a purely data flow construct, whereas the proposed one mixes data flow 
and control flow.

Waddaya all think?

        Cheers,
        --MarkM