How to use a structural type with common parameters?

I have two case classes

case class StringCaseClass(argument: String) case class IntCaseClass(argument: Int) 

I want to define a structural type that will correspond to 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 to do this? If I redefine the structural type to have specific types for A and R, it will compile correctly, but then I lose flexibility

+6
source share
3 answers

Comment by @aloiscochard is almost absent. He forgot to mention that the objects of the companion class already implement the corresponding FunctionN attribute, so you can just do it,

 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) 
+9
source

In general, you should avoid structural typing, as it is very expensive. The call will be converted to a reflection call due to restrictions in the JVM. When you start using scala 2.10, structural types will cause a warning at compile time (although you can disable this with a flag).

If you are learning a more general way of adding functionality to classes that don’t share the inheritance hierarchy, you can use type classes.

Here is an 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 are trying to accomplish, but maybe you can do what you want with a type class, and that will be much faster.

+3
source

You have not passed an instance of StringCaseClass to your method . What you passed there is a StringCaseClass companion StringCaseClass (which is automatically generated for case classes).

Try it if this works: method(StringCaseClass("dummy")) .

0
source

All Articles