<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I like this. One question: what does this new theory have to say about the situation</div><div class=""><br class=""></div><div class="">switch (x) {</div><div class=""> case Foo(int x):</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>int y = x;</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>// fall through</div><div class=""> case Bar(int x, int y):</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>…</div><div class="">}</div><div class=""><br class=""></div><div class="">? Perhaps it is forbidden because the “int y” in the pattern would shadow the “int y” in the earlier declaration? Or can the two be merged?</div><div class=""><br class=""></div><div class="">—Guy</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 20, 2017, at 1:17 PM, Brian Goetz <<a href="mailto:brian.goetz@oracle.com" class="">brian.goetz@oracle.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" class="">
<div text="#000000" bgcolor="#FFFFFF" class="">
<div class="moz-text-flowed" style="font-family: -moz-fixed;
font-size: 14px;" lang="x-unicode">
<br class="">
We had a long meeting regarding scoping and shadowing of pattern
variables. We ended up in a good place, and we were all a bit
surprised at where it seems to be pointing.<br class="">
<br class="">
We started with two use cases that we thought were important:
<br class="">
<br class="">
Re-use of binding variables:
<br class="">
<br class="">
switch (x) {
<br class="">
case Foo(var a): ... break;
<br class="">
case Bar(var a): ...
<br class="">
}
<br class="">
<br class="">
Short-circuiting tests:
<br class="">
<br class="">
if (!(x matches Foo(var a))
<br class="">
throw new NotFooException();
<br class="">
// use a here
<br class="">
<br class="">
We had a few nice-to-haves:
<br class="">
- that binding variables should be ordinary variables, not
something new;
<br class="">
- that binding, when assigned, be final
<br class="">
<br class="">
Where we expected to land was something like:
<br class="">
- binding variables are treated as blank finals
<br class="">
- binding variables are hoisted into a synthetic block, which
starts right before the statement containing the expression
defining the binding
<br class="">
- it is permitted for locals to shadow other locals that are DU
at the point of shadowing. (This, as a bonus, would rescue the
existing unfortunate scoping of local variables defined in switch
blocks.)
<br class="">
<br class="">
We thought this was a sensible place to land because it built on
the existing notion of scoping and local variables. The remaining
question, it seemed, was: "where does this synthetic scope end."
<br class="">
<br class="">
First, a note about where the scope starts. Consider:
<br class="">
<br class="">
if (e1 && x matches Foo(var a)) {
<br class="">
...
<br class="">
}
<br class="">
<br class="">
Logically, we'd like to start the scope for `a` right where it is
first declared; this is how locals work. But, if we want to
maintain the existing concept of local variable scope, it has to
start earlier. The latest candidate is right before the if
starts; we act as if there is an invisible { ... } containing the
entirety of the if statement, and declare `a` there.
<br class="">
<br class="">
This means, though, that the scope of `a` includes `e1`, even
though `a` is declared later. This is confusing, but maybe we can
ignore this, and provide a clear diagnostic if the user stumbles
across it.
<br class="">
<br class="">
So, where does the scope end? The obvious candidate is right
after the if statement. This means `a` is in scope for the entire
if-else, but, because it is DU in the else-blocks, can be reused
if we adopt the "shadowing OK if DU" rule.
<br class="">
<br class="">
FWIW, the "shadowing ok if DU" rule is clever, and gives us the
behavior we want for switch / if-else chains with patterns, but
has some collateral damage. For example, the following would
become valid code:
<br class="">
<br class="">
int x; // declared but never used
<br class="">
float x = 1.0f; // acceptable shadowing of int x
<br class="">
<br class="">
Again, maybe we can ignore this. But where things really blew up
was attempting to handle the short-circuiting if case:
<br class="">
<br class="">
if (!(x matches Foo(var a))
<br class="">
throw new NotFooException();
<br class="">
// use a here
<br class="">
<br class="">
For this to work, we'd have to extend the scope to the end of the
block containing the if statement. Now, given our "shadowing is
OK if DU rule", this is fine, right? Not so fast. In this
simpler case:
<br class="">
<br class="">
if (x matches Foo(var b)) { }
<br class="">
// try to reuse b here, I dare you
<br class="">
<br class="">
we find that
<br class="">
- B is neither DU nor DA after the if, so we can't shadow it;
<br class="">
- B is final and not DU, so we can't write to it;
<br class="">
- B is not DA, so we can't use it.
<br class="">
<br class="">
In other words, B is a permanent toxic waste zone, we can neither
use, nor redeclare, nor assign it. Urk.
<br class="">
<br class="">
Note too that our scoping rule is not really about unbalanced ifs;
it's about abrupt completion. This is reasonable too:
<br class="">
<br class="">
if (x matches Foo(var a)) {
<br class="">
println("Matched!");
<br class="">
}
<br class="">
else
<br class="">
throw new NotFooException();
<br class="">
// reasonable to use a here too!
<br class="">
<br class="">
Taking stock: our goal here was to try and use normal scopes and
blank final semantics to describe binding variables, out of a
desire to not introduce new concepts. But it's a bad fit; the
scope may be unnaturally large on the beginning side, and wherever
we set the end of the scope, we end up in a choice of bad
situations (either something we want in scope is not, or something
we don't want in scope is.) So traditional scopes are just a bad
approximation, and what we gain in "reusing familiar concepts", we
lose in the mismatch.
<br class="">
<br class="">
<br class="">
STEPPING BACK
<br class="">
<br class="">
What we realized at this point is that the essence of binding
variables is their <span class="moz-txt-underscore"><span class="moz-txt-tag">_</span>conditionality<span class="moz-txt-tag">_</span></span>. There is not a single
logical old-style scope that describes the right set of places for
a binding to be in scope, but there is a well-defined control-flow
analysis that tells us exactly where we can use the binding, and
where we can't. This is the flow-scoping construct we initially
worried was too "new and different." But, after some further
thought, and a few tweaks, this seems exactly what we want, and I
think can be made understandable.
<br class="">
<br class="">
The basic idea behind flow-scoping is: a binding variable is in
scope where it is well-defined, and not in scope when it is not.
We'll provide a complete calculus, but the key thing to understand
is that the rules of flow scoping are just plain old DA/DU; if a
binding is DA, then it is well-defined.
<br class="">
<br class="">
In particular, flow-scoping can handle abrupt termination
naturally; for a statement:
<br class="">
<br class="">
if (x matches Foo(var a)) { A }
<br class="">
else { B }
<br class="">
C
<br class="">
<br class="">
the scope of `a` includes A, and also includes C iff B completes
abruptly. We can easily explain this as:
<br class="">
- if x matches Foo(var a), we execute the A block, and in this
case `a` is clearly well-defined (as we'd not execute A if the
match failed);
<br class="">
- The only way to reach C, if B completes abruptly, is if the
match succeeds, so `a` is well defined during C in this case too.
<br class="">
<br class="">
Because the scope of a binding variable is precisely the cases in
which it is well defined, there is no need to tinker with
shadowing.
<br class="">
<br class="">
Conditional variables can now always be final, because they will
never be in scope and not DA.
<br class="">
<br class="">
Similarly, folding reachability into scoping for conditional
variables also means that fallthrough has a well-defined meaning.
If we have:<br class="">
<br class="">
case Foo(int x): ... break;<br class="">
case Bar(int x): ....<br class="">
<br class="">
then the Bar case is not reachable from where x would be
initialized, so the first x is not in scope when the second x is
declared, and everything is great. On the other hand:<br class="">
<br class="">
case Foo(int x): ... no break ...<br class="">
case Bar(int x): ... A ...<br class="">
<br class="">
now x is well-defined in A, no matter how we got there. (The
merging of the two xs is the same merging we have to do anyway for
"if (x matches Foo(int a) || x matches Bar(int a)".) <br class="">
<br class="">
<br class="">
People had originally expressed concern that flow-scoping leaves a
scope "with holes", and allows puzzlers with shadowing of fields.
(This is the "swiss cheese" problem.) For example:
<br class="">
<br class="">
// Field
<br class="">
String s
<br class="">
<br class="">
if (!(x matches String s)) {
<br class="">
a(s);
<br class="">
}
<br class="">
else {
<br class="">
b(s);
<br class="">
}
<br class="">
<br class="">
This would be confusing because the `s` passed to a() is the
field, but the `s` passed to b() is the binding. But, there's a
really simple way to prevent this: do not allow conditional
variables to shadow fields or locals. Now, there is no chance of
this confusion, and this is not a big constraint, because the
names of conditional variables are strictly local. (Further, we
can disallow shadowing of in-scope conditional variables by locals
(or other conditional variables.))
<br class="">
<br class="">
<br class="">
Scorecard:
<br class="">
- Relatively straightforward to spec, as we have a clean calculus
for flow-scoped conditional variables;
<br class="">
- Relatively straightforward to implement (our prototype already
does this);
<br class="">
- One new concept: conditional variables;
<br class="">
- Conditional vars are scope where they make sense, and not in
scope where they do not, cannot be assigned to (always DA and
final when in scope), and are never in scope when not DA;
<br class="">
- No changes to shadowing;
<br class="">
- Meets all the target use cases.
<br class="">
<br class="">
<br class="">
</div>
<br class="">
<br class="">
<div class="moz-cite-prefix">On 11/3/2017 6:44 AM, Gavin Bierman
wrote:<br class="">
</div>
<blockquote type="cite" cite="mid:27805597-0665-41D9-996D-6BEBA77B8ADA@oracle.com" class="">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" class="">
<h2 id="scopes" style="box-sizing: border-box; margin-bottom:
16px; line-height: 1.225; padding-bottom: 0.3em; color: rgb(51,
51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI',
Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI
Emoji', 'Segoe UI Symbol'; margin-top: 0px !important;" class="">Scopes</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Java has five constructs that introduce fresh variables
into scope: the local variable declaration statement, the for
statement, the try-with-resources statement, the catch block,
and lambda expressions. The first, local variable declaration
statements, introduce variables that are in scope for the rest
of the block that it is declared in. The others introduce
variables that are limited in their scope.</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">The addition of pattern matching brings a new
expression, <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">matches</code>,
and extends the <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">switch</code> statement.
Both these constructs can now introduce fresh (and, if the
pattern match succeeds, definitely assigned (DA)) variables. But
the question is <em style="box-sizing: border-box;" class="">what
is the scope of these ‘pattern’ variables</em>?</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Let us consider the pattern matching constructs in
turn. First the <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">switch</code> statement:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">switch (o) {
case int i: ...
case ..
}</code></pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">What is the scope of the pattern variable <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">i</code>?
There are a range of options.</p>
<ol style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="" type="1">
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope of the pattern
variable is from the start of the switch statement until the
end of the enclosing block.</p><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">In this case the pattern
variable is in scope but would be definitely unassigned (DU)
immediately after the switch statement.</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">switch (o) {
case int i : ... // DA
... // DA
case T t : // i is in scope
}
... // i in still in scope and DU</code></pre>
</li>
</ol>
<ul style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="">
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Simple</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> Can’t
simply reuse a pattern variable in the same switch statement
(without some form of shadowing)</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> Pattern
variable poisons the rest of the block</li>
</ul>
<ol start="2" style="box-sizing: border-box; padding: 0px 0px 0px
2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51,
51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI',
Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI
Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="" type="1">
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope of the pattern
variable extends only to the end of the switch block.</p><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">In this case the pattern
variable would be considered DA only for the statements
between the current case label and the subsequent case
labeled statement. For example:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">switch (o) {
case int i : ... // DA
... // DA
case T t : // i is in scope but not DA
}
... // i not in scope</code></pre>
</li>
</ol>
<ul style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="">
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Simple</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Pattern
variables not poisoned in subsequent statements in the rest of
the block</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Similar
technique to <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">for</code> identifiers
(not a new idea)</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> Can’t
simply reuse a pattern variable in the same switch statement
(without some form of shadowing)</li>
</ul>
<ol start="3" style="box-sizing: border-box; padding: 0px 0px 0px
2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51,
51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI',
Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI
Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="" type="1">
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope of the pattern
variable extends only to the next case label.</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">switch (o) {
case int i : ... // in scope and DA
... // in scope and DA
case T i : // int i not in scope, so can re-use
}
... // i not in scope</code></pre>
</li>
</ol>
<ul style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="">
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Simple
syntactic rule</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Allows
reuse of pattern variable in the same switch statement.</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> Doesn’t
make sense for fallthrough</li>
</ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class=""><strong style="box-sizing: border-box;" class="">NOTE</strong> This
final point is important - supporting fallthrough impacts on
what solution we might choose for scoping of pattern variables.
(We could not support fallthrough and instead support OR
patterns - a further design dimension.)</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class=""><strong style="box-sizing: border-box;" class="">ASIDE</strong> Should
we support a <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">switch</code> <em style="box-sizing: border-box;" class="">expression</em>; it
seems clear that scoping should be treated in the same way as it
is for lambda expressions.</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">The <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">matches</code> expression
is unusual in that it is an <em style="box-sizing: border-box;" class="">expression</em> that introduces a fresh variable.
What is the scope of this variable? We want it to be more than
the expression itself, as we want the following example code to
be correct:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (e matches String s) {
System.out.println("It's a string - " + s);
}</code></pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">In other words, the variable introduced by the pattern
needs to be in scope for an enclosing IfThen statement.</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">However, a <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">match</code> expression
could be nested within another expression. It seems reasonable
that the patterns variables are in scope for at least the rest
of the expression. For example:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">(e matches String s || s.length() > 0) </code></pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Here the <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s</code> should
be in scope for the subexpression <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s.length</code> (although
it is not DA). In contrast:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">(e matches String s && s.length() > 0)</code></pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Here the <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s</code> is
both in scope and DA for the subexpression <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s.length</code>.</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">However, what about the following:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (s.length() > 0 && e matches String s) {
System.out.println(s);
}</code></pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Given the idea that a pattern variable flows from the
inside-out to the enclosing statement, it would appear that <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s</code> is
in scope for the subexpression <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s.length</code>;
although it is not DA. Unless we want scopes to be
non-contiguous, we will have to accept this rather odd situation
(consider where <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">s</code> shadows
a field). [This appears to be what happens in the current C#
compiler.]</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">Now let’s consider how far a pattern variable flows wrt
its enclosing statement. We have a range of options:</p>
<ol style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="" type="a">
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope is both the
statement that the match expression occurs in and the rest
of the block. In this scenario,</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (o matches T t) {
...
} else {
...
}</code></pre><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">is treated as equivalent to
the following pseudo-code (where <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">match-and-bind</code> is
a fictional pattern matching construct that pattern-matches
and binds to a variable that has already been declared)</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">T t;
if (o match-and-bind t) {
// t in scope and DA
} else {
// t in scope and DU
}
// t in scope and DU</code></pre><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">This is how the current C#
compiler works (although the spec describes the next option;
so perhaps this is a bug).</p>
</li>
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope is just the
statement that the match expression occurs in. In this
scenario,</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (o matches T t) {
...
} else {
}
...</code></pre><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">is treated as equivalent to
the pseudo-code</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">{ T t;
if (o match-and-bind t) {
// t in scope and DA
} else {
// t in scope and DU
// thus declaration int t = 42; is not allowed.
}
}
// t not in scope
...</code></pre>
</li>
</ol><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="">This restricted scope allows reuse of pattern
variables, e.g.</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (o matches T x) { ... }
if (o matches S x) { ... }</code></pre>
<ol start="3" style="box-sizing: border-box; padding: 0px 0px 0px
2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51,
51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI',
Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI
Emoji', 'Segoe UI Symbol'; font-size: 16px;" class="" type="a">
<li style="box-sizing: border-box;" class=""><p style="box-sizing: border-box; margin-top: 16px;
margin-bottom: 16px;" class="">The scope of the pattern
variable is determined by a flow analysis of the enclosing
statement. (It could be thought of as a refinement of option
b.) This is currently implemented in the prototype compiler.
For example:</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal;" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">if (!!(o matches T t)) {
// t in scope
} else {
// t not in scope
}</code></pre>
</li>
</ol>
<ul style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51);
font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial,
freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol'; font-size: 16px;" class="">
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Code
will work in the presence of most refactorings</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> We
have this code working already :-)</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> This
is a break to the existant notion of scope as a contiguous
program fragment. A scope can now have holes in it. Will users
ever understand this? (Although they are <em style="box-sizing: border-box;" class="">very</em> similar
to the flow-based rules for DA/DU.)</li>
</ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom:
16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue',
Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color
Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px;" class=""><strong style="box-sizing: border-box;" class="">ASIDE</strong> Regardless
of whether we opt for (b) or (c) we may consider a further
extension where we allow the scope to extend beyond the current
statement for the case of an unbalanced <code style="white-space: pre; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">if</code> statement.
For example</p>
<pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 16px; font-stretch: normal; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class="">```
if (!(o matches T t)) {
return;
}
// t in scope
...
return;
```</code></pre>
<ul style="box-sizing: border-box; padding: 0px 0px 0px 2em;
margin-top: 0px; color: rgb(51, 51, 51); font-family: 'Helvetica
Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
font-size: 16px; margin-bottom: 0px !important;" class="">
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">+ve</strong> Supports
a common idiom where else blocks are not needed</li>
<li style="box-sizing: border-box;" class=""><strong style="box-sizing: border-box;" class="">-ve</strong> Yet
further complication of notion of scope.</li>
</ul>
<div class=""><br class="">
</div>
</blockquote>
<br class="">
</div>
</div></blockquote></div><br class=""></body></html>