Translation of pattern matching
John Rose
john.r.rose at oracle.com
Mon Aug 7 21:43:52 UTC 2017
On Aug 4, 2017, at 6:55 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>
> Thanks Maurizio,
> so there is no need to an uber carrier, because you compose the carrier (as far as I understand).
Yes. It is a FooHandle sort of thing, stateless and composable, from a nominal source.
>
> You still need a way to pass the carrier from indy to the switch.
I think I am beginning to understand what you mean by uber-carrier.
We need a way to perform enough pattern matching in the indy
(before the tableswitch) to determine which case to branch into.
This in turn may require (partial or complete) evaluation of one
or more cases. This in turn *will* require the creation of one (or
more?) case-specific carrier objects (T -> Ci via the i-th case pattern).
Such a partial carrier *cannot* be discarded because it cannot
be reconstructed (risk of race conditions and redundant computation).
This means that the indy must produce a *single value* which implies
(a) the number i of the selected case, and (b) any carrier value Ci
needed to complete the evaluation of the i-th case. And (for grins)
(c) a way to get any *other* carrier values Cj for any j-th case which
may be reachable from fall-through from the i-th case. (Are we
having fun yet? Maybe we can safely say that Cj can be computed
from scratch after Ci falls through. I'm not certain yet, and I don't
want to design it out.)
This means that the indy result has to return something which
(in general) carries as much info as an ADT (disjoint union of
several product types). And maybe more (simultaneous values
from several branches of such a union).
Here's an example (indy stands for "invokedynamic or ldc/invokeExact"):
T t = …;
static final Extractor X = EXTRACTOR[T];
Object /*C0*/ c0 = indy[X.SETUP](t); // is this the uber-C ??
int i = indy[X.CLASSIFIER](c0);
// could use for(;;) or similar here to handle switch fallthrough
switch (i) {
…
case 42:
Object /*C42*/ c42 = indy[X.CASE(42).SETUP](t, c0);
assert(1 == indy[X.CASE(42).CLASSIFIER](t, c0));
String a = indy[X.CASE(42).COMPONENT(0)](t, c0);
int b = indy[X.CASE(42).COMPONENT(1)](t, c0);
char[] c = indy[X.CASE(42).COMPONENT(2)](t, c0);
…
}
There is a two-level structure here simply because the component
sets are different in the different cases. Perhaps it can be factored
into a two-level application of a single Extractor pattern, but the
"arrows" say that the first level is a classic sum-of-products ADT,
while the second level is just a product component extraction
(this is why the "assert" shows up on the second level).
My argument breaks down if you can "push" all the carrier
extraction logic into each case, *after* the "i" value is determined.
But this is no more than a feeble hope. You can't, in general.
At the very least, the thing returned at the top of the switch
must be one of the carrier types for the selected switch,
*plus* the number of that switch. So each carrier type
carries an extra few bits of information for "i".
(This kind of ad hoc stuff is why I am proposing ArgumentList.
MHs are good for ad hoc stuff, and ALs are a missing bit of MHs.)
> I think I will test the ArgumentList translation to see how it goes,
> did I mention that prototyping things with mjolnir was easier :)
Maybe I should commit Mjolnir to our test repo as a more honorable
replacement for Indify? :-)
— John
More information about the amber-dev
mailing list