Marvin Sielenkemper sent me a bug report in private mail. The bug and its
immediate solution are obvious, but Swaroop and I noticed a larger issue in
discussion, and I want to discuss it.
Marvin's original bug reported that:
(try e1 (catch excpt-id (otherwise e2 (throw excpt-id))))
failed with a syntax error. There were two problems:
1. A catch block without any explicitly caught exceptions was syntactically
illegal. This has been fixed.
2. The identifier excpt-id was not in scope within an otherwise clause. It
*should* be in scope there having type (undiscriminated) Exception. This is
also a straightforward bug, and it is being addressed.
But discussion quickly caused us to notice a related problem. The following
does not work:
(try e1
(catch excpt-id (excpt-tag e2 (throw excpt-id))
...))
because THROW wants an argument of type Exception, and inside the scope of
the catch leg, the type of excpt-id is some particular exception leg type.
This means that once you catch an exception, you have to construct a new
exception instance in order to re-throw:
(try e1
(catch excpt-id (excpt-tag1 e2 (throw (excpt-tag1 excpt-id.content)))
...)
At first glance, this seems awkward, but not fatal. There are two problems
with it:
1. Since exceptions are reference types, this approach mandates storage
allocation at the point of re-throw. In some programs storage allocation is
not permissible.
2. In future, a single catch clause may catch multiple exception types
(using the same trick as DEFREPR), so figuring out which exception
constructor to run is a minor nuisance.
For both reasons, it would be very pleasant to be able to just hand excpt-id
to THROW. It is not difficult to generalize THROW to accept either an
exception or an exception leg interchangeably, and this was the solution
that I initially proposed.
But this got us to thinking about the fact that an exception leg can be
viewed as a dependent subtype of type Exception, and a union leg can
similarly be viewed as a dependent subtype of the containing union type, and
if these things were in fact subtypes, why not just permit an explicit
upcast of some form?
The key points are this:
1. The SWITCH construct (therefore the CATCH construct) makes a *copy* of
the original union/exception instance.
2. If a union is of reference type, there is no way to overwrite its
representation, because DEREF only accepts types of the form (ref 'a), which
does not include union or structure reference types. In consequence, the tag
type of a by-reference union instance cannot change after construction.
Because this is true (a) the union instance is type-stable, and therefore
(b) reference to the leg type can safely point to the original storage, and
(c) there is no problem holding a by-ref reference into the middle of a
by-reference union.
3. If a union is of value type, then the *copy* that is made by SWITCH has
some leg type, the copy is not aliased, and the leg type is type stable. In
this case the leg type is simply an ordinary structure type with a hidden
slot for the tag field.
What this all means is that if U is a union type, and U.L is a "leg type"
for U, then:
U := U.L can be copy compatible with no problems
U(e:U.L) can be treated as a value constructor. In the case of a
by-value union
it makes a copy. In the case of a by-reference union it returns
the original
pointer value and allocates no storage.
It also means that there is no reason to restrict the escape of the type U.L
from inside a SWITCH -- U.L is a perfectly valid structure type, except that
it has a weirdly constant tag field. We are NOT going to extend the language
to make U.L a first-class type at this time, and we are NOT going to
introduce this copy compatibility rule at this time, but we reserve the
right to do so in the future.
What we ARE going to do in the short term is allow an expression having leg
type as an argument to THROW, with the meaning: "upcast this leg type back
to Exception and throw the result". This is a temporary expedient to
eliminate the storage allocation concern.
By the way, there is an incredibly awkward workaround that is possible in
the language already once we fix the existing problem with the OTHERWISE
clause:
(try e1
(catch excpt-id
(otherwise
(switch expct-tag excpt-id
... do your cases here, but you can (raise excpt-id) ...))))
except that we think there is another bug here because SWITCH probably won't
accept exceptions at the moment. That also needs to be fixed at some point,
but it's not high on the priority list.
For the moment, we're going to hack THROW to accept exception leg types, and
leave the rest as a problem/opportunity for the future.
shap
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev