Mixing Common Types

I would like to use generic types in myTest

case class CC(i:Int, s:String, s2:String) case class Value[V](value: V) def myTest[F](values: (CC ⇒ Value[F])*) = Unit class QF[M](x: M) { def eqs(v: M) = Value(x) } implicit def conversion[V](v: V): QF[V] = new QF(v) myTest(_.i eqs 1) myTest(_.s eqs "lol") myTest(_.s eqs "lol", _.s2 eqs "lol2") 

It works up to this point, but I think I get a covariance error when I try to use mix types.

When I do this:

 myTest(_.i eqs 1, _.s eqs "lol") 

I get the following error:

 Error:(16, 13) type mismatch; found : A$A135.this.CC => A$A135.this.Value[Int] required: A$A135.this.CC => A$A135.this.Value[Any] myTest(_.i eqs 1, _.s eqs "lol");} ^ 
+4
source share
3 answers

Yes this is correct. Since Value defined as invariant in V , this means that Value[Int] and Value[String] are not subtypes of Value[Any] , but Any is the closest common supertype of Int and String , i.e. F in myTest . Since V is in a covariant position, you can simply change this:

 case class Value[+V](value: V) 
+5
source

Not covariance, but existential types. In your function

 def myTest[F](values: (CC ⇒ Value[F])*) = Unit 

F can vary from a call to myTest to another, but is fixed inside the argument list (CC ⇒ Value[F])* . Types of arguments in your examples:

 scala> val i_eqs = (cc : CC) => cc.i eqs 1 i_eqs: CC => Value[Int] = <function1> 

where F then Int .

 scala> val s_eqs = (cc : CC) => cc.s eqs "lol" s_eqs: CC => Value[String] = <function1> 

where F is String . It works for all three examples, because F same for all elements in the argument list. But when you call

 myTest(_.i eqs 1, _.s eqs "lol") 

the compiler tries to combine CC => Value[Int] (the type of the first argument) into CC => Value[String] (the second argument), which reduces to unifying Value[Int] with Value[String] . Indeed, you can define Value as a covariant, and this is probably a good idea. But I assume that you really want to express here that myTest arguments are a "list CC => Value[F] for some type F , which may differ from the argument to another in the list. :) A longer version is probably understandable:

 scala> def myTest(values: (CC ⇒ Value[F] forSome { type F } )*) = Unit myTest: (values: CC => Value[_]*)Unit.type 

The added forSome { type F } states that there exists an F for which the argument is of type CC => Value[F] , but "forget" that F So, Value[Int] will become Value[F] for the unknown F , as well as Value[String] . From the side they become the same, so they work. This syntax, although very clear, can be shortened most of the time with an underscore:

 scala> def myTest(values: (CC ⇒ Value[_])*) = Unit myTest: (values: CC => Value[_]*)Unit.type 
+2
source

Override myTest as follows:

 def myTest(values: CC => Value[_]*) = Unit 

Thus, each function object passed to myTest will have a suitable type parameter for Value , which it returns.

If you use covariance (for example, Value[+V] ), you can replace Value with Any , since the Scala compiler will supply Any as an inference type for F to myTest[F] , and you will lose many types of validation.

+1
source

All Articles