scalacovariancehigher-order-functionsunit-typebottom-type

why is () => () not a subtype of Nothing => ()


In scala, functions are covariant in their output type, and contravariant in their input type.

For example, if Dog is a subtype of Animal, then

T => Dog is a subtype of T => Animal, and Animal => T is a subtype of Dog => T

In other words, a producer of Dog can go where a producer of Animal is expected, and a consumer of Animal can go where a consumer of Dog is expected.

So why do I get this compile error:

def useF(f: Nothing => Unit): Unit = ()
def f(x: Unit): Unit = ()
useF(f) // ok
useF(() => ()) // error

/*
example.scala:4: error: type mismatch;
 found   : () => Unit
 required: Nothing => Unit
useF(() => ())
*/

I thought that Nothing is a subtype of Unit, so () => () should be a subtype of Nothing => (), since () => () is of type Unit => Unit. What is the difference in type signature between f and () => ()?


Solution

  • Your logic is correct. Just syntax is wrong.

    () => T is not Function1[Unit, T]. It is actually a syntax for lambda with no argument which results in Function0[T]. The parenthesis here is not Unit. It's a syntax to denote zero arguments

    The correct way to construct a Unit => Unit is:

    (_: Unit) => Unit
    

    You can add explicit type annotation to verify:

    val f: Function1[Unit, Unit] = _ => ()
    useF(f)
    // No error