Reputation: 728
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
Upvotes: 6
Views: 883
Reputation: 23056
@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)
Upvotes: 9
Reputation: 1480
In general you should avoid structural typing as it's very expensive. The call will be converted into a reflection call because of limitations in the JVM. When you start using scala 2.10 structural types will result in a warning at compile time (though you could disable that using a flag).
If you're looking into a more general way to add functionality to classes that don't share an inheritance hierarchy you could use Type Classes.
Here's a quick example:
trait CanCreateRFromA[A,R]{
def createNew(a:A): R
}
implicit object CanCreateBlahFromInt extends CanCreateRFromA[Int,Blah2]{
def createNew(i:Int):Blah2 = new Blah2(i)
}
implicit object CanCreateBlah1FromString extends CanCreateRFromA[String,Blah1]{
def createNew(s:String):Blah1 = new Blah1(s)
}
case class Blah1(something:String)
case class Blah2(something:Int)
def createRFromA[A,R](a:A)(implicit tc:CanCreateRFromA[A,R])= tc.createNew(a)
Then you can call:
createRFromA(1) // This gives a Blah2
createRFromA("1") // This gives a Blah1
Again I'm not sure what you're trying to accomplish, but it probably is possible to do what you want with a type class and it will be much faster.
Upvotes: 3
Reputation: 10764
You didn't pass an instance of StringCaseClass
to your method
. What you passed there is companion object of StringCaseClass
(which is automatically generated for case classes).
Try if this works: method(StringCaseClass("dummy"))
.
Upvotes: 0