scalagenericstype-constraintshigher-kinded-typestype-constructor

Type constructor bounded by proper type


Consider the following type parameter clause [F[_] <: Int] in

def h[F[_] <: Int] = ???

where a type constructor F is bounded by the proper type Int. Now both h[List] and h[Int] are illegal

scala> def h[F[_] <: Int] = ???
     |
def h[F[_] <: Int]: Nothing

scala> h[List]
        ^
       error: type arguments [List] do not conform to method h's type parameter bounds [F[_] <: Int]

scala> h[Int]
         ^
       error: Int takes no type parameters, expected: 1

so why is then [F[_] <: Int] legal?


Solution

  • The type parameter declaration F[_] <: Int means that every instantiation of F must be a subtype of Int. It's right in the syntax, though cryptic: F does not have to be a subtype of Int; F[_] has to be a subtype of Int (for all types that may be placed in the _). An example of such an F is one which always returns Int:

    type ConstInt[X] = Int
    h[ConstInt] // compiles
    

    Note that you can name the type in the _. E.g. I can declare a type parameter F[X] <: X. X is local to the declaration, defined by appearing under F on the left, used as a bound on the right, and going out of scope afterwards. This example means that F[X] must be a subtype of X, e.g. as in

    def f[F[X] <: X] = ???
    type Identity[X] = X
    f[Identity] // works
    type ConstNothing[X] = Nothing
    f[ConstNothing] // works
    // f[ConstInt] (ConstInt[X] = Int is not always a subtype of X; counterexample X = AnyRef)
    

    Perhaps that drives home what the bound is supposed to mean.