简体   繁体   中英

Why does map/filter … not work with an Array of Nothing?

Isn't Nothing a subtype of all types?

scala> val array = new Array(5)
array: Array[Nothing] = Array(null, null, null, null, null)

scala> array.map(_ => 42)
<console>:9: error: value map is not a member of Array[Nothing]
       array.map(_ => 42)
             ^

scala> array.filter(_ != 42)
<console>:9: error: value filter is not a member of Array[Nothing]
       array.filter(_ != 42)
             ^

It's weird that this doesn't work.

Is this specified, a feature or a bug?

When you see weird behavior involving Nothing, it's because the type inference algorithm thinks that it inserted Nothing itself, since it is introduced during type inference: if nothing is known about a type variable then it is bounded by Any and Nothing. It has long been on my list of things to do to see if I can introduce a new internal-only bottom type for that purpose so user-level Nothing and inference-level Nothing are not intermingled, but it's a pretty ambitious task. Still, I might now be hardcore enough to try it.

I suspect Scala shouldn't let you do that kind of Array[Nothing] instantiation. There are by definition no instances of nothing around, yet your array looks like it's filled with Nothing s that are null, but null is not a valid value for Nothing . This for instance fails with the error type mismatch; found: Null(null) required: Nothing type mismatch; found: Null(null) required: Nothing

val n: Nothing = null

So I'd expect to run into trouble each time you can actually fool the system to believe you are finally getting hold of a much sought for instance of Nothing

Here's another weird case. Run this:

object Main {

  class Parametrized[T] { var value: T = _ }

  def main(args: Array[String]) {
    val p = new Parametrized // typed as Parametrized[Nothing]
    val n = p.value  // n is now actually an instance of Nothing... isn't it?
    println(p.value) // prints null, but null is not an instance of Nothing
    println(n)       // throws NullPointerException...
  }

}

Note that the Scala Array type is invariant. So Nothing being a subtype of everything may not be relevant.

Also map and filter are not defined on Array . Implicit conversions in Predef are used to provide such methods for arrays.

So the compiler is unable to find an implicit conversion from Array[Nothing] to something that has the map or filter defined. Using the REPL, I can actually see that such an implicit conversion should be available:

scala> val conv = implicitly[Array[Nothing] <%< collection.mutable.ArrayOps[Nothing]]

conv: <%<[Array[Nothing],scala.collection.mutable.ArrayOps[Nothing]] = <function1>

scala> conv(new Array[Nothing](5)).filter(_ => true)
res8: Array[Nothing] = Array(null, null, null, null, null)

So the question becomes why the compiler does not consider the genericArrayOps conversion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM