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

2019-02-18 20:03发布

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?

3条回答
做自己的国王
2楼-- · 2019-02-18 20:06

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.

查看更多
Evening l夕情丶
3楼-- · 2019-02-18 20:20

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 Nothings 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

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...
  }

}
查看更多
Lonely孤独者°
4楼-- · 2019-02-18 20:25

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.

查看更多
登录 后发表回答