Search code examples
scalaabstract-type

Can I provide a default value for an abstract type in Scala?


I have a class like this:

abstract class CrudResource extends Controller {
  type ResourceIdType


  def getAction(id: ResourceIdType) = ...
  def deleteAction(id: ResourceIdType) = ...

  ...
}

which is intended to be used like so:

class Payees extends CrudResource {
  type ResourceIdType = Int

  ...
}

I'd like to default the ResourceIdType to Int, like so:

abstract class CrudResource extends Controller {
  type ResourceIdType = Int

  ...
}

so that the ID type will be Int unless a subclass overrides it like so:

override type ResourceId = String

but this fails to compile with:

error: overriding type ResourceIdType in class CrudResource, which equals Int;
 type ResourceIdType has incompatible type
       class Payees extends CrudResource { override type ResourceIdType = String }

Is it possible to do what I'm trying to do? I tried, in CrudResource, type ResourceIdType <: Any = Int, but that's not valid syntax.


Solution

  • That would be a violation of the liskov substitution principle. Let's assume you can do it.

    abstract class CrudResource extends Controller {
      type ResourceIdType = Int
      def resources: List[ResourceIdType] = ???
      def getAction(id: ResourceIdType) = ???
      def deleteAction(id: ResourceIdType) = ???
    }
    
    class Payees extends CrudResource {
      override type ResourceIdType = String
    }
    
    class Trouble {
      var resource: Controller.ResourceIdType
    }
    val trouble = new Trouble
    val crudResource: CrudResource = new Payee
    trouble.resource = crudResource.resources.head // assigning String to Int var!
    

    However, you are halfway to a cake pattern. If you define ResourceId as an abstract nested class, you could have subclasses implementing them in terms of Int or String, as long as its API doesn't expose the specific types.