[e-lang] MatchBindExpr wierdness

Mark S. Miller markm at cs.jhu.edu
Mon May 1 01:30:40 EDT 2006


The MatchBindExpr is an odd duck. In all other circumstances *except* the 
MatchBindExpr, match-failure causes a non-local exit, preventing control flow 
from continuing into the scope where variable defined by the pattern would be 
visible. This is even true for typical uses of MatchBindExpr as well, such as:

     if ([i, j] =~ [x, y :char]) {
         ... x ... y ...
     } else {
         # x and y are not in scope
     }

However, because the MatchBindExpr evaluates to a boolean, if this boolean 
isn't immediately used by an 'if' as above, then the question arises of what 
values should 'x' and 'y' have when the pattern match fails. Dean has 
identified two stances to take: "incremental" binding vs. "atomic" binding.

Let's say 'i' and 'j' both currently hold integers. Integers do not 
auto-coerce to characters, causing the above match to fail when attempting to 
match the 'y :char' sub-pattern. The issue is, this failure occurs after the 
'x' pattern match has succeeded, binding 'x' to the value of 'i'. In the scope 
following the MatchBindExpr as a whole, 'y' is bound to a broken reference. 
But what is 'x' bound to? Incremental binding says that all variables already 
bound stay bound. Atomic binding says that all variable bound by a failed 
pattern match are broken in the scope following the MatchBindExpr.

E-on-Java currently seems to provide atomic binding:

     ? [1,2] =~ [x, y :char]
     # value: false

     ? y
     # value: <ref broken by problem: <ClassCastException: \
     #         Integer doesn't coerce to a Character>>

     ? x
     # value: <ref broken by problem: <ClassCastException: \
     #         Integer doesn't coerce to a Character>>

If MatchBindExpr provided incremental binding, the value of 'x' would have 
been 1. Although the above session is consistent with atomic binding, further 
examination shows that E-on-Java's current behavior is just buggy:

     ? var q := 0
     # value: 0

     ? [1,2] =~ [x ? (q := fn{x}; true), y :char]
     # value: false

This pattern match succeeds or fails exactly when the previous one would, and 
results in the same bindings for 'x' and 'y'. However, within the context 
where 'x' is bound to 1, it creates and stores a closure which captures the 
'x' variable. Since the 'x' variable that was captured was bound to 1 and is 
final, it should still be bound to 1 when we call 'q'.

     ? q()
     # value: <ref broken by problem: <ClassCastException: \
     #         Integer doesn't coerce to a Character>>

This reveals that the E-on-Java's current MatchBindExpr implementation, on the 
failure case, breaks all variables defined by the pattern, regardless of 
whether they've already been bound.

To implement correct incremental binding, we'd need to somehow skip breaking 
those variable already successfully bound. To implement correct atomic 
binding, we'd have to consider the 'x' within the pattern and the 'x' visible 
after the MatchBindExpr to be different 'x' variables. The first 'x' is 
successfully bound to 1, whereas the second 'x' becomes bound to a broken 
reference.

My next email will show Kevin's proposed expansion of MatchBindExpr to Dean's 
proposed trinary-define expression. By taking MatchBindExpr out of Kernel-E, 
Kernel-E itself no longer needs to break variables on match failure, and so 
avoids the whole incremental vs. atomic weirdness. Kevin's proposed expansion 
of MatchBindExpr provides atomic binding. We should also examine expansions 
that provide incremental binding.

-- 
Text by me above is hereby placed in the public domain

     Cheers,
     --MarkM



More information about the e-lang mailing list