[patterns] on treatment of null
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Jul 7 16:42:21 UTC 2017
On 07/07/17 17:04, Dmitry Petrashko wrote:
>
> On 7 Jul 2017, at 17:17, Maurizio Cimadamore wrote:
>
> I understand. In our mind, 'var' is simply a way to tell the
> compiler "type missing here, please fill it out" - and we'd like
> to keep the type inference as orthogonal as possible from other
> related semantics.
>
> This is also how it behaves in scala if you don’t ascribe the type in
> pattern. The type will be filled in by typer. Based on
> http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
> <http://cr.openjdk.java.net/%7Ebriangoetz/amber/pattern-match.html>
>
> |exprswitch(b) { case Box(var n) -> n; }; |
>
> is equivalent to this in Scala:
>
> |x match { case Box(n) => n; }; |
>
> Or am I misinterpreting?
>
They are the same yes. What I was trying to say, is that when there's no
manifest type you seem to let 'null' in (because of the lack of
instanceof under the hood), so two similarly looking patterns have
different behavior w.r.t. nulls, which I'm not wild about (but I have
never noticed it either having used Scala :-))
>
> In Scala, the runtime uses |instanceof| test (Option 1 in your
> writeup),
> while the exhaustivity checkers uses type system and assumes
> absence of null (Option 2).
> For generics, we issue a warning that type parameters are
> unchecked.
> Have you considered this option?
>
> So, you are saying that Scala does option 1 - but it tones it a
> bit down by emitting a warning (rather than an harsh error) when
> generic types are found.
>
> This seems a sensible option - the only thing I don't understand
> from your description - what does Scala do for nested patterns? Is
> it another instanceof? If that's the case, does it means that I
> cannot match against a List whose head is null with a normal
> nested type test pattern?
>
> Scala behaves the same way for top level and nested patters:
>
Yep - that's what I feared :-)
I think that, basically, the differences we're seeing here is that my
claim that 'case var t' is just a shorthand for 'case T t' is not as
obvious as I thought it would have been.
In Scala var patterns and test patterns are two different things, and
treated in quite different ways (which means different null behavior).
As I said in my earlier email, I have a feeling that keeping 'var'-ness
out of the equation might result in better compositionality (after all,
patterns are not the only place where we intend to use 'var').
Maurizio
>
> Lets say that we have |case class Cons(hd: Object, tl: Cons)|
>
> |x match { case Cons(a, b) => 1 // will match only if `x instanceof
> Cons`. will match even if a is null and b is null case Cons(a, b:
> Cons) => 2 // will not match if b is null, but a may be null case a:
> Cons => 3 // will not match null, is equivalent to the first option
> case a => 4 // always matches } |
>
> now, details about type parameters and type inference:
>
> |case class Cons[T](hd: T, tl: Cons) x match { case Cons(a, b) => 1 //
> a will be inferred to be Any, our top type case Cons[Int](a, b) => 2
> // warning will be emitted that Cons[Int] is unchecked. } |
>
> In practice, people rarely see this warning due to important
> observation that compiler uses:
>
> |case class Cons[T](hd: T, tl: Cons) extends Seq[T] val x: Seq[Int] =
> ??? x match { case Cons[Int](a, b) => 2 // a warning will not be
> emitted, as we know that T is the same as in Seq and we “trust” x. } |
>
> Best,
> Dmitry
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20170707/3515dbf8/attachment.html>
More information about the amber-spec-experts
mailing list