Question: Why can't I match on a Seq.empty?

Question

Why can't I match on a Seq.empty?

Answers 2
Added at 2017-01-04 23:01
Tags
Question

I tried matching a seq like this:

val users: Seq[User] = ....

users match {
  case Seq.empty => ....
  case ..
}

I got an error saying:

stable identifier required, but scala.this.Predef.Set.empty found.

Can someone explain why I can't do this? i.e. the theory behind it

Answers to

Why can't I match on a Seq.empty?

nr: #1 dodano: 2017-01-04 23:01

Match on Seq() or Nil instead:

scala> Seq.empty
res0: Seq[Nothing] = List()

scala> val a = Seq(1,2,3)
a: Seq[Int] = List(1, 2, 3)

scala> val b = Seq()
b: Seq[Nothing] = List()

scala> a match {case Seq() => "empty"
     | case _ => "other"
     | }
res1: String = other

scala> b match {case Seq() => "empty"
     | case _ => "other"
     | }
res2: String = empty

See @jwvh's answer for technical reasons why.

nr: #2 dodano: 2017-01-05 00:01

Both Seq.apply and Seq.empty are implemented in GenericCompanion, which has no unapply method, so you'd think that pattern matching wouldn't be possible, but you're still able to pattern match on Seq() because Seq.unapplySeq(), implemented in SeqFactory, makes that available.

From the unapplySeq() docs:

This method is called in a pattern match { case Seq(...) => }.

more background

Collections make pattern matching possible via the unapplySeq() method, which gets called when the compiler sees something like case List() => ....

It's interesting that List(42) is the same thing as List.apply(42) but not so in pattern matching:

lst match {
  case List(8)       => ...  // OK
  case List.apply(8) => ...  // won't compile
}

The same principle applies to Seq() and Seq.empty.

Source Show
◀ Wstecz