In Scala, it's possible to specify whether a function or class is covarient or contravarient in the following manner
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
What are the real world uses of this feature?
I know the compiler runs checks to make sure that the stated entity is actually covarient or otherwise, but what is the benefit of even adding such annotations?
The simplest case where your probably already using it without knowing it is the scala collections.
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
Imagine you have the following hierarchy:
class A
class B extends A
Covariance. Covariant type can be used as return type:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
So you can use any of Foo[DerivedClass]where Foo[BaseClass] is used, because anywhere Foo[BaseClass].getArg is called BaseClass is expected as result and any DerivedClass can be returned and assigned to it.
Contravariance. Contravariant type can be used as method parameter type:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
Again. You can use any of Bar[DerivedClass] where Bar[BaseClass] is used, because anywhere Bar[DerivedClass].setArg(p: DerivedClass) is called DerivedClass is expected as argument and any Bar[BaseClass] can be used in this context, because you can always pass DerivedClass to Bar[BaseClass].setArg(p: BaseClass).
Related
I use the factory pattern with generics. The idea is to create the right implementation (BlockType1Impl or BlockType2Impl) depending on the type of A which is a case class( BlockchainType1 or BlockchainType2). I don't put any Type Bounds constraints.
Code
After looking at this example on the apply method with generic types
trait BlockTypeFactory[A]{
def findTransactions( blocks: Seq[A], address: String): Seq[TransactionResponse]
}
object BlockTypeFactory{
// I want this method to return the correct implementations
def getBlockExplorer[A](blockType: A): BlockTypeFactory[A] = {
blockType match {
case type1: BlockchainType1 => new BlockTypeFactory[BlockchainType1](new BlockType1Impl)
// error : Expression of type BlockTypeFactory[BlockType1Impl] doesn't conform with the expected type BlockTypeFactory[A]
case type2: BlockchainType2 => new BlockType2Impl
}
}
def apply[A](implicit ev: BlockTypeFactory[A],blockType: A):BlockTypeFactory[A] = ev
}
But I get an error about expected type . What is exactly wrong ?
Other classes
class BlockType1Impl extends BlockTypeFactory[BlockchainType1]
class BlockType2Impl extends BlockTypeFactory[BlockchainType2]
case class BlockchainType1(...)
case class BlockchainType2(...)
Your code doesn't work because the compiler doesn't know where to get the implicit instances of BlockTypeFactory.
In order to achieve your goal you can use Type Classes.
This way is extensible, you can have more than one factory per class if you want (you need to play with implicits scope) and you can define standard factories for some types.
You can code implicit instances of your case classes inside BlockTypeFactory object, but this is the way it is usually done.
// your type class
trait BlockTypeFactory[A] {
def create:A
}
case class BlockchainType1()
object BlockchainType1 {
// type 1 impl
implicit val factory:BlockTypeFactory[BlockchainType1] = new BlockTypeFactory[BlockchainType1] {
def create: BlockchainType1 = BlockchainType1()
}
}
case class BlockchainType2()
object BlockchainType2 {
// type 2 impl
implicit val factory:BlockTypeFactory[BlockchainType2] = new BlockTypeFactory[BlockchainType2] {
def create: BlockchainType2 = BlockchainType2()
}
}
object BlockTypeFactory {
// get factory
def apply[A:BlockTypeFactory]:BlockTypeFactory[A] = implicitly[BlockTypeFactory[A]]
// or create
def create[A:BlockTypeFactory]:A = implicitly[BlockTypeFactory[A]].create
}
val instance1 = BlockTypeFactory[BlockchainType1].create
val instance2 = BlockTypeFactory.create[BlockchainType2]
This pattern is called Type Class, and it is used to get ad hoc polymorphism. In your example, you need a polymorphic method findTransactions for each class defined on BlockTypeFactory.
What difference does the compiler see in BroFinder1 and BroFinder2 that causes the first one to fail? I really need BroFinder1 to work as it is without utilizing patterns such as Aux Pattern.
trait Brother[I] {
type Bro
def get: Bro
}
class Foo
object Foo {
implicit object bro extends Brother[Foo] {
override type Bro = Bar
override def get = new Bar
}
}
class Bar {
def barSpecificAction(): Unit = ()
}
class BroFinder1[I](implicit val b: Brother[I]) {
def brotherOf: b.Bro = b.get
}
class BroFinder2[I] {
def brotherOf(implicit b: Brother[I]): b.Bro = b.get
}
new BroFinder1[Foo].brotherOf.barSpecificAction() // Doesn't compile
//error: Error:(73, 32) value barSpecificAction is not a member of _1.b.Bro
//new BroFinder1[Foo].brotherOf.barSpecificAction();
^
new BroFinder2[Foo].brotherOf.barSpecificAction() // Ok
//scala version: 2.12.4
This is not a perfect answer but probably will provide some insights. The issue seems to be not related to implicit at all. It seems to be related to another fairly advance Scala feature: path-dependent types. Particularly the trouble seems to come from the fact that Scala type system is not powerful enough to express type difference between finder1 and finder2 precisely in following code:
object Foo {
implicit object bro extends Brother[Foo] {
override type Bro = Bar
override def get = new Bar
}
object bro2 extends Brother[Foo] {
override type Bro = Foo
override def get = new Foo
}
}
val finder1 = new BroFinder1[Foo]
val finder2 = new BroFinder1[Foo]()(Foo.bro2)
val bof1 = finder1.brotherOf
val bof2 = finder2.brotherOf
Sidenote: the fact that some parameter is implicit doesn't make it a "constant" because you can always pass the parameter explicitly anyway or you can have different visible implicit values in different contexts.
AFAIU the most precis type the finder1 or finder2 might be assigned in this example is just BroFinder1[Foo]. Particularly there is no way to catch different values of the b implicit variable and thus there is no way to pass further exactly the value of the path-dependent type that is encoded inside that value. Thus the best compiler knows about the types of bof1 and bof2 is that they both have type in form of _1.b.Bro where _1 means some particular instance of BroFinder1[Foo]. And so the compiler can't be sure that bof1 is actually of type Bar while bof2 is of type Foo.
The second example works because implicit parameter is captured in the same context so compiler knows exactly what the result type of brotherOf is.
The only workaround I know is not exactly suitable in your case: use "Aux" type. If your BroFinder took also an explicit parameter of type Foo, the solution might have looked like this:
type BrotherAux[I, B] = Brother[I] {type Bro = B}
class BroFinder3[I, B](val v: I)(implicit val b: BrotherAux[I, B]) {
def brotherOf: B = b.get
}
new BroFinder3(new Foo).brotherOf.barSpecificAction()
But in your case it has to be much less helpful
class BroFinder1[I, B](implicit val b: BrotherAux[I, B]) {
def brotherOf: B = b.get
}
new BroFinder1[Foo, Bar].brotherOf.barSpecificAction()
Because new BroFinder2[Foo].brotherOf is of type Bar and Bar has method barSpecificAction but new BroFinder1[Foo].brotherOf is of existential type
x.Bro forSome { val x: Brother[Foo] }
and it doesn't have method barSpecificAction.
I have a generic method which a generic type parameter T which is a subclass of MyClass. Inside that method, I want to create e new instance of T, how can I do that?
This doesn't work (because of type erasure):
object Demo extends App {
def myMethod[T <: MyClass](): Unit = {
val t = new T // gives error: class type required by T found
}
myMethod[MySubclassA]()
}
abstract class MyClass
class MySubclassA extends MyClass
class MySubclassB extends MyClass
It fails to work, but not (primarily) because of type erasure, but because your definition should make sense for all T which satisfy the type bounds, and new T doesn't. E.g. T can be MyClass or an abstract subclass, or a subclass without a parameter-less constructor, or a trait (traits can extend classes), or...
If a runtime error is good enough, you can go with Sergey Lagutin's solution. But more reasonable for most cases would be to pass some way to create a T to myMethod. Possibly as an implicit argument, e.g.
class Factory[T](f: () => T) {
def make(): T = f()
}
object Factory {
implicit val MySubclassAFactory =
new Factory(() => new MySubclassA)
implicit val MySubclassBFactory =
new Factory(() => new MySubclassB)
}
def myMethod[T <: MyClass](implicit factory: Factory[T]): Unit = {
val t = factory.make()
...
}
myMethod[MySubclassA] // works
myMethod[MyClass] // compilation error
myMethod[ASubclassForWhichFactoryIsNotDefined] // compilation error
You may use ClassTag to achieve your goal:
def myMethod[T <: MyClass : ClassTag]: T =
implicitly[ClassTag[T]].runtimeClass.newInstance().asInstanceOf[T]
println(myMethod[MySubclassA]) // MySubclassA#66d2e7d9
println(myMethod[MySubclassB]) // MySubclassB#1efbd816
I have few classes which do not derive from any superclass. They all have bunch of same methods defined. For example,
class A {
def getMsgNum = 1
}
class B {
def getMsgNum = 2
}
I would like to write a generic function that will return message num based on object function is called with. So something like,
def getMsgNum[T](t: T) = t.getMsgNum
I think that because of type erasure I cannot expect that to work but I was looking at view bound and context bound with ClassTag but that still does not work.
def getType[T: ClassTag](msg: T) = {
msg.getMsgNum
}
I come from C++ background and I am trying to achieve something to the effect of template compilation for every type.
Thanks for your time!
I personally prefer adhoc polymorphism with TypeClass (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html) pattern. I think it will be much more "true scala way" solution for this kind of problem. Also structural typing more expensive at runtime because it use reflection for field access.
class A
class B
trait ToMsgNum[T] {
def getMsgNum: Int
}
implicit object AToMsgNum extends ToMsgNum[A] {
def getMsgNum = 1
}
implicit object BToMsgNum extends ToMsgNum[B] {
def getMsgNum = 2
}
def getMsgNum[T: ToMsgNum](t: T) =
implicitly[ToMsgNum[T]].getMsgNum
println(getMsgNum(new A))
println(getMsgNum(new B))
def getMsgNum[T](t: T)(implicit ev: T => { def getMsgNum: Int }) = t.getMsgNum
where { def getMsgNum: Int } is a structural type. From the documentation:
A structural type is a type of the form Parents { Decls } where Decls contains declarations of new members that do not override any member in Parents.
and
Structural types provide great flexibility because they avoid the need to define inheritance hierarchies a priori
Please note that the above solution uses an implicit reflective call to access the field of the structural type, a language feature that has to be explicitly enabled by adding the import
import scala.language.reflectiveCalls
This is not too different from Eugene's solution but I think it's a bit clearer:
// predefined classes you have no access to
class Foo { def someMethod = "foo" }
class Bar { def someMethod = "bar" }
there's no way in Scala other than reflection or structural types (which is reflection in disguise) to generically call someMethod on these types. The way this can be made to work though, is by defining adapter objects that know how to deal with each type individually, and you then make generic calls on those instead:
trait HasSomeMethod[T] { def someMethod(x: T): String }
object FooHasSomeMethod extends HasSomeMethod[Foo] { def someMethod(x: Foo) = x.someMethod }
object BarHasSomeMethod extends HasSomeMethod[Bar] { def someMethod(x: Bar) = x.someMethod }
now you can pass one of those adapter objects into the method that needs generic access to Foo#someMethod and Bar#someMethod:
def invokeSomeMethod[T](x: T)(adapter: HasSomeMethod[T]) =
adapter.someMethod(x)
invokeSomeMethod(new Foo)(FooHasSomeMethod) // returns "foo"
invokeSomeMethod(new Bar)(BarHasSomeMethod) // returns "bar"
(we could have used a single parameter list here but later we'll nede 2 lists anyway)
however, this is obviously not as useful as we'd like as we have to pass in the adapter manually. Let's introduce implicits to make Scala automatically look up the right adapter object and pass that in to our generic but inheritance'less method:
implicit object FooHasSomeMethod extends HasSomeMethod[Foo] { ... }
implicit object BarHasSomeMethod extends HasSomeMethod[Bar] { ... }
def invokeSomeMethod[T](x: T)(implicit adapter: HasSomeMethod[T]) =
adapter.someMethod(x)
now these work:
invokeSomeMethod(new Foo) // returns "foo"
invokeSomeMethod(new Bar) // returns "bar"
The above 2 calls get translated automatically to the longer calls in the previous version; Scala looks up suitable values for the implicit adapter parameter automatically from the implicit objects (and also vals and defs, to be precise) available in the "environment" of the call.
You can also define invokeSomeMethod like this, which is just syntactic sugar over the above definition:
def invokeSomeMethod[T: HasSomeMethod](x: T) =
implicitly[HasSomeMethod[T]].someMethod(x)
or, since T: HasSomeMethod auto-generates a second parameter list implicit evidence$1: HasSomeMethod[T], this also works:
def invokeSomeMethod[T: HasSomeMethod](x: T) =
evidence$1.someMethod(x)
The above "pattern" is known as Type Classes. So for example the T: HasSomeMethod bit can be read as "some type T that belongs to the type class HasSomeMethod" (or "...has been made an instance of the type class HasSomeMethod").
For more on Type Classes, see e.g. http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html.
You can also define the HasSomeMethod type class instance for classes that don't even have someMethod nor bear no other resemblance to Foo and Bar whatsoever, if needed:
implicit object IntHasSomeMethod extends HasSomeMethod[Int] {
def someMethod(x: Int) = "this is an int: " + x
}
invokeSomeMethod(3) // returns "this is an int: 3"
If you need to define an instance of that type class for many classes, you can have a helper (with a name that matches the type class, for niceness):
def HasSomeMethod[T](fn: T => String) = new HasSomeMethod[T] {
def someMethod(x: T) = fn(x)
}
now you can define type class instances (adapters) very concisely:
implicit val FooHasSomeMethod = HasSomeMethod[Foo](_.someMethod)
implicit val BarHasSomeMethod = HasSomeMethod[Bar](_.someMethod)
implicit val IntHasSomeMethod = HasSomeMethod[Int]("this is an int: " + _)
implicit val PersonHasSomeMethod = HasSomeMethod[Person](_.name)
// etc
If you dont want to use structural type (reflection) and implicit, how about create Adaptor on top of it, so you own method getMsgNum will implement based on the Adaptor instead of already existing class.
class A {
def getMsgNum = 1
}
class B {
def getMsgNum = 2
}
class C {
def getMsgNum = 3
}
trait Adaptor[T] {
def getMsgNum: Int
}
class AdaptorA(t: A) extends Adaptor[A] {
def getMsgNum = t.getMsgNum
}
class AdaptorB(t: B) extends Adaptor[B] {
def getMsgNum = t.getMsgNum
}
class AdaptorC(t: C) extends Adaptor[C] {
def getMsgNum = t.getMsgNum
}
def getMsgNum[T](t: Adaptor[T]) = t.getMsgNum
getMsgNum(new AdaptorA(new A)) //1
getMsgNum(new AdaptorB(new B)) //2
getMsgNum(new AdaptorC(new C)) //3
I have a covariant Scala type Thing[+B]. The implementation uses an internal mutable queue:
private val queue : AsyncQueue[B]()
AsyncQueue is a custom mutable queue implementation, with special properties which I can't easily implement in an immutable version. Because it's mutable, AsyncQueue is invariant. So I can't use it in my covariant type Thing.
Since queue is private, I can guarantee the correctness of my code: e.g. I won't try to assign queue to a reference of type Queue[Any]. How can I make this work, keeping Thing covariant in B, without using casts?
(The solution with casts is to declare an AsyncQueue[Object] and cast objects on enqueue/dequeue, which is very ugly.)
ETA: I understand type covariance, and I understand why I shouldn't be able to declare an AsyncQueue of a covariant type, or make AsyncQueue itself covariant. My question is how to design this code to avoid using casts everywhere.
You can make your member immune to the variance check by making it private[this], according to the spec.
scala> trait Thing[+A] { def next(): A }
defined trait Thing
expectedly,
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
<console>:12: error: covariant type A occurs in invariant position in type => scala.collection.mutable.ArrayBuffer[A] of value as
class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
but
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { private[this] val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
defined class Thingie
and
scala> class X
defined class X
scala> val xs = new Thingie[X]
xs: Thingie[X] = Thingie#49f5c307
scala> xs.next
res1: X = X#4816c290
You need #uncheckedVariance:
import scala.annotation.unchecked.uncheckedVariance
class A[T] {}
class B[+T] {
val a: A[T #uncheckedVariance] = null
}
Even the Scala standard library makes use of #uncheckedVariance, notably in allowing the invariant mutable collections to inherit from covariant traits.
If B is covariant in Thing[+B] then you will not be able to have B in a contravariant position in Thing, i.e.
def put(b:B) {...} // will fail to compile, can't use a covariant type in this position
But it is possible to make two interfaces for Thing, one where the type is used in covariant positions and one where it is used in contravarient positions, as in the following:
trait ThingProduce[+B] {
def get: B
}
trait ThingConsume[-B] {
def put(b: B)
}
class Thing[B] extends ThingConsume[B] with ThingProduce[B] {
private val queue = new scala.collection.mutable.Queue[B]
def put(b: B) {queue.enqueue(b)}
def get: B = queue.dequeue
def both(b: B): B = ???
}
So that with the class hierarchy:
class Animal
class Mammal extends Animal
class Dog extends Mammal
The following can be done:
val mammalThing: Thing[Mammal] = new Thing[Mammal]{}
val dogConsumer: ThingConsume[Dog] = mammalThing
val animalProducer: ThingProduce[Animal] = mammalThing
But not:
val dogConsumer: ThingConsume[Dog] = animalProducer
//or
val animalProducer: ThingProduce[Animal] = dogConsumer
Thus Thing[B] can be seen to be both covarient and contravariant, but only for certain members.