<div dir="auto"><div>Hello!<br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jan 26, 2023, 23:01 Stephen Colebourne <<a href="mailto:scolebourne@joda.org">scolebourne@joda.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
In the Motivation section it is claimed that because `byte b = 42`<br>
compiles, it implies that sometimes an `int` can be converted to a<br>
`byte` without a cast. This is nonsense. In this context, `42` is<br>
*not* an `int` at all - it is a literal. There is no conversion here,<br>
`42` is typed as a `byte` because of the assignment. `42` is never, at<br>
any stage, an `int`. At the very least, the JEP should be amended to<br>
remove this part of the Motivation section.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">A small correction: this is not what spec says. 42 is accepted here not because it's untyped literal but because it's a compile time constant expression that fits the byte type. Other constant expressions are also accepted here, like:</div><div dir="auto"><br></div><div dir="auto">byte b = 21 + 21; // obviously not literal</div><div dir="auto">Or even:</div><div dir="auto">final int x = 21;</div><div dir="auto">final int y = 21; // int type is even spelled explicitly</div><div dir="auto">byte b = x + y;</div><div dir="auto"><br></div><div dir="auto">With best regards,</div><div dir="auto">Tagir Valeev </div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
The document proceeds to argue that because switch works with Object<br>
hierarchies:<br>
  Pet p = new Pet(new Dog()); // automatic widening conversion from<br>
Dog to Animal<br>
  switch (p) {<br>
    case Pet(Dog d)    -> ... d ...<br>
    case Pet(Animal a) -> ... a ...<br>
    default            -> ...<br>
  }<br>
that it must therefore be OK to work with primitives:<br>
  int i = methodReturningShort();<br>
  switch (i) {<br>
    case byte  b -> ... b ...;<br>
    case float f -> ... f ...;<br>
    default      -> -1;<br>
  }<br>
<br>
There is simply no comparison here. Dog and Animal are subtypes of<br>
Pet, a concept that has been baked into the language since day one,<br>
and is fully understood by all. By contrast, there is absolutely no<br>
subtyping relationship between int, byte and short, and again this<br>
fact has been baked into the language since day one.<br>
<br>
There is a *huge* red line being crossed here. Values in Java have two<br>
distinct parts - the type and the value of the instance. Java has<br>
always kept these two things completely separate: General-purpose<br>
language features operate on types and references/null (eg.<br>
instanceof, catch, switch) or expressions (if, for, while). It<br>
requires an expression or an operator for the actual value of the<br>
instance to be considered. The JEP proposes to shatter that boundary,<br>
saying that the language should now examine not only the type but also<br>
the value of the instance in order to determine flow control.<br>
<br>
The root cause of the issue here is trying to treat Object hierarchy<br>
conversion and conversion between different primitive types as being<br>
somehow equivalent. They are not. Java does not have a mechanism that<br>
allows a LocalDate to be assigned to a String, even though there is a<br>
perfectly reasonable way to do so. Instead, you have to explicitly<br>
perform the conversion by calling toString(). That is because<br>
`LocalDate` and `String` are separate types with no subtype hierarchy.<br>
Similarly, there is no subtype hierarchy link between `int` and<br>
`long`. That an `int` can be assigned to a `long` is merely a<br>
convenience - it could have required a method call. Critically though,<br>
the convenience conversion is absolute. No runtime check of the value<br>
of the instance is required. This even applies when converting `int`<br>
to `float` which is lossy.<br>
<br>
In my view, the only pattern matching checks that make sense here are<br>
those in line with the separation between types and values of<br>
instances. This basic rule implies:<br>
* `int` vs `Integer` and vice versa - OK, as only requires examination<br>
of the type and reference/null<br>
* `int` vs `byte` - not OK, as an expression is required in order to<br>
extract the value of the `int` in order to decide flow control<br>
<br>
In summary, if this was simply about adding a niche feature for<br>
checking whether an `int` actually fits in a `byte` I would have no<br>
problem. For example, were the pattern match to be based on an<br>
expression (ie. a method call) then I would have no problem. The key<br>
issue here is the red line being crossed by having a general-purpose<br>
language feature examine the value of the instance outside of an<br>
expression.<br>
<br>
thanks<br>
Stephen<br>
</blockquote></div></div></div>