Search code examples
scalagenericsstructural-typing

How do I use a structural type with generic parameters?


I have two case classes

case class StringCaseClass(argument: String)

case class IntCaseClass(argument: Int)

I want to define a structural type which will match the companion object of both of these

type HasApply1 {
  def apply[A, R](argument: A): R
}

This will compile fine, but when I try to use it like this

def method(caseClass: HasApply1) {
  // whatever
}

method(StringCaseClass)

I will get a compiler error

found   : StringCaseClass.type
required: WithApply1
            (which expands to)  AnyRef{def apply[A, R](string: A): R}

Is there any way of accomplishing this? If I redefine the structural type to have concrete types for A and R it will compile correctly, but then I lose the flexiblity


Solution

  • @aloiscochard's comment is almost there. What he forgot to mention is that case class companion objects already implement the appropriate FunctionN trait, so you can simply do this,

    scala> case class StringCaseClass(argument: String)
    defined class StringCaseClass
    
    scala> case class IntCaseClass(argument: Int)
    defined class IntCaseClass
    
    scala> def method[A, R](caseClass: A => R, a: A) = caseClass(a)
    method: [A, R](caseClass: A => R, a: A)R
    
    scala> method(StringCaseClass, "foo")
    res0: StringCaseClass = StringCaseClass(foo)
    
    scala> method(IntCaseClass, 23)
    res1: IntCaseClass = IntCaseClass(23)