[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