Search code examples
scalainheritancemixins

Scala: "class type required but {trait} with {trait} found" when inheriting from mixin type alias


I have a very common type alias defined:

package object policy {

  type KeyGen[K] = Function0[K] with Serializable
}

But when I try to inherit from it:

import java.security.Key
case class FixedKeyGen(key: Key) extends KeyGen[Key] {

  override def apply(): Key = key
}

The maven compiler gave me the following error:

[ERROR] /home/peng/git/datapassport/core/src/main/scala/com/schedule1/datapassport/policy/ValueMapping.scala:16: class type required but () => java.security.Key with Serializable found
[ERROR] case class FixedKeyGen(key: Key) extends KeyGen[Key] {
[ERROR]                                          ^
[ERROR] /home/peng/git/datapassport/core/src/main/scala/com/schedule1/datapassport/policy/ValueMapping.scala:16: com.schedule1.datapassport.policy.KeyGen[java.security.Key] does not have a constructor
[ERROR] case class FixedKeyGen(key: Key) extends KeyGen[Key] {

What is going on here?


Solution

  • I don't think you're allowed to extend a compound type directly like that. That is, Function0[K] with Serializable isn't a class type in and of itself. It is a compound type without a constructor, and that's the key. It doesn't really make sense to extend something without a constructor. The type alias does something similar to this (note the parentheses around the type):

    case class FixedKeyGen(key: Key) extends (Function0[Key] with Serializable) {
        override def apply(): Key = key
    }
    

    We get the same error:

    <console>:20: error: class type required but () => java.security.Key with Serializable found
           case class FixedKeyGen(key: Key) extends (Function0[Key] with Serializable) {
    

    This is because Function0[Key] with Serializable isn't a class type.

    But, this of course works if I remove the parentheses. Without them, FixedKeyGen is extending Function0 and mixing Serializable. With them, it's trying to extend a compound type.

    To work around this, you may want to just use a trait, instead:

    trait KeyGen[K] extends Function0[K] with Serializable
    
    case class FixedKeyGen(key: Key) extends KeyGen[Key] {
        override def apply(): Key = key
    }