简体   繁体   中英

When is Nothing a legal receiver?

Being the subtype of every other type allows a hypothetical Nothing typed value to be passed to any function. However, although such a value can serve as receiver for toString() it can't for unary_! (among others).

object Foo {
    def dead(q: Nothing): Unit = {
        println(q);
        q.toString();
        ((b: Boolean) => !b)(q);
        !q; // value unary_! is not a member of Nothing
    }
}

Is this a bug or a feature?

Note:

  1. This is the Scala version of an equivalent question I asked on Kotlin .
  2. Upcasting works: !(q.asInstanceOf[Boolean])

You don't need upcasting. You only have to ascribe some type which has a method unary_! :

def dead(q: Nothing): Unit = {
  !(q: Boolean)
}

Without an explicit type ascription, the method unary_! simply cannot be resolved, because even though Nothing is a subtype of Boolean , it's not a subclass of Boolean , therefore the compiler can not find a method unary_! in the inheritance hierarchy of Nothing .

The fact that you can define such methods and functions is not a bug either. The following is a completely valid program that uses a function with input type Nothing to produce a perfectly meaningful result 0 , without throwing any errors or anything like it:

def foo[X](xs: List[X], f: (Int, X) => Int) = {
  xs.foldLeft(0)(f)
}

foo(Nil, (i: Int, n: Nothing) => 42)

The presence of Nothing in the type system is a Really Good Idea, because it's an initial object (for each other type A , there is exactly one function Nothing => A ), and it simplifies lot of things, because it does not force you to deal with all kind of strange corner cases.

Nothing is a subtype of every other type (including scala.Null); there exist no instances of this type

In other words, there are no values of type Nothing . So contrary to the statement in your question, you can't pass a Nothing typed value to any function (even hypothetically) because it doesn't exist, by definition. Neither can it be a receiver for any method because, again, it doesn't exist.

So the bug, if there is one, is that the compiler does not warn you that you have created a function that can never be called.


In this case, println(q) works because Nothing is a subtype of Any , and q.toString works because of an implicit conversion of AnyRef to Object which supports toString . The inline function converts q to Boolean which is also OK, but Object does not support unary_! so !q fails to compile.

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