Scala: how to force type to be provided

347 Views Asked by At

Lets say we have the following trait and class definition

trait Model extends Product
class X[T <: Model] {}

Give the above I can create instance of X as follows.

val x = new X

The compiler does not complain. The inferred type in this case is Nothing. I would like to know how can I prevent this at compile time so that it is not allowed to create instances of X without providing an explicit type i.e is a subtype of Model?

2

There are 2 best solutions below

0
Juh_ On

I think this works:

trait Model
case class M() extends Model // one subclass of Model, for testing

// use implicit to force T to be convertible to Model
// which works for actual Model subclasses but not Nothing
class X[T<:Model](implicit f: (T) => Model)

new X
  error: type mismatch;
  found   : <:<[Nothing,Nothing]
  required: T => Model

new X[M] // ok

However you can still explicitly gives Nothing as type-arg (strange...):

new X[Nothing] // ok

I would go for the above, but an other idea is to explicitly pass as parameter the class of the Model subclass:

class X[T<:Model](tClass: Class[T])

new X(classOf[M]) // ok

new X(classOf[Nothing])
  error: type mismatch;
  found   : Class[Nothing](classOf[scala.Nothing])
  required: Class[T]
  Note: Nothing <: T, but Java-defined class Class is invariant in type T.
  You may wish to investigate a wildcard type such as `_ <: T`. (SLS 3.2.10)
4
Ramesh Maharjan On

class X[T <: Model] {} class definition means T type has upper bound as Model type. And Nothing is subtype for all the rest of the types. Thats the reason Scala compiler is not complaining.

Make the type T of class X a contravarient as

class X[-T <: Model] {}

so that when you define

val x = new X 

it is treated by Scala compiler as

x: X[Model] = X@7c9bdee9