What does [+A] mean in Scala class declaration? [duplicate] - scala

This question already has answers here:
Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?
(4 answers)
Closed 7 years ago.
In scala Option class is declared like
sealed abstract class _Option[+A]
case object _None extends _Option[Nothing] {}
final case class _Some[+A](x: A) extends _Option[A] {}
What is [+A]? Why not just [A]? Could it be [-A] and what it would mean?
Sorry if it is a duplicate but I couldn't find the answer on SO.

It declares the class to be covariant in its generic parameter. For your example, it means that Option[T] is a subtype of Option[S] if T is a subtype of S. So, for example, Option[String] is a subtype of Option[Object], allowing you to do:
val x: Option[String] = Some("a")
val y: Option[Object] = x
Conversely, a class can be contravariant in its generic parameter if it is declared as -A.
Read above variances in Scala in the docs here.

Related

An issue with generics types in method parameters

can someone explain why the code below doesn't work?
scala> abstract class A[T] {}
defined class A
scala> class B {}
defined class B
scala> object C extends A[B] {}
defined object C
scala> def method(arg: A[Any]): Unit = {}
method: (arg: A[Any])Unit
scala> method(C)
<console>:14: error: type mismatch;
found : C.type
required: A[Any]
Note: B <: Any (and C.type <: A[B]), but class A is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
method(C)
I have an abstract class, here named A, and I'd like to be able to pass anything that extends A[AnythingHere] as an argument to the method method. In Java I would write public void method(A<?> arg) {}, but I don't know how to make it work with Scala, as there is no ?.
I also tried adding that + to the +T, but after testing and searching for what it does, I didn't find it helpful here. Just the warning disappeared
Thanks in advance
The code does not work because if you want to use generics in variant or contravariant in Scala, you have to declare it explicitly. Otherwise, the Java invariant behaviour is implemented.
Java is by default invariant. This means that if A < B, thenList[A] and List[B] do not have any hierachical relationship between them.
Scala lets you to use declare generic type as covariant or contravariant, which means
If you declare a generic as covariant, then if if A < B, thenList[A] < List[B]. To do this, you have to declare the generic using the syntax class A[+T]
If you declare a generic as contravariant, then if if A < B, thenList[A] > List[B]. To do this, you have to declare the generic using the syntax class A[-T]
You probably want to use: def method[T](arg: A[T])
This means that you don't need to change the variance of the class definition.

Why asInstanceOf doesn't initiate implicit conversion? [duplicate]

This question already has answers here:
What are the differences between asInstanceOf[T] and (o: T) in Scala?
(4 answers)
Closed 8 years ago.
I have a case class with a companion object.
I have implicit conversion method inside the companion object.
case class Foo(p:T)
object Foo {
implicit def Foo2Bar(foo: Foo): Bar = new Bar(doSmth(foo.p))
}
I have a method with a param of type Object. I want to pass an instance of Bar there.
Unfortunatelly, the following code doesn't do the conversion but throws ClassCastException:
import Foo._
...
val foo = createFoo()
bazz(foo.asInstanceOf[Bar])
At the same time, the next (more verbose) code do the job:
import Foo._
...
val foo = createFoo()
val bar: Bar = foo
bazz(bar)
Any ideas why the former code doesn't work?
asInstanceOf deals only with subtype relationships, but defining an implicit conversion doesn't create a subtype relationship.

why Buffer[String] can not inherit from Buffer[AnyRef] [duplicate]

This question already has answers here:
Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?
(4 answers)
Closed 8 years ago.
class Test1(buf:Buffer[AnyRef])
class Test2(buf:Buffer[String]) extends Test(buf)
Compiler error:
type mismatch;
found : scala.collection.mutable.Buffer[String]
required: scala.collection.mutable.Buffer[Any]
Note: org.msgpack.type.Value <: Any, but trait Buffer is invariant in type A. You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
Short answer: You can't add AnyRef to Buffer[String]:
val b: Buffer[AnyRef] = Buffer[String]()
b += new Object // ???
Buffer[String] can't be Buffer[AnyRef] because Buffer[T] is not covariant on type parameter T. It can't be declared covariant (Buffer[+T]) because there is usage of T in contravariant position (for instance in += method).

Use of abstract type in a concrete class? [duplicate]

This question already has answers here:
Concrete classes with abstract type members
(2 answers)
Closed 9 years ago.
scala> class A { type T <: String; def f(a: T) = println("foo")}
defined class A
scala> (new A).f("bar")
<console>:9: error: type mismatch;
found : java.lang.String("bar")
required: _1.T where val _1: A
(new A).f("bar")
^
Class A has an abstract type T, but is not an abstract class. Creating an object of A (as shown) does not define type T.
My first thought was, I am allowed to pass any type as T which is a subclass of String, but I am not. So what type actually is T in the object and what am I allowed to pass through ?
As you say, T in A is abstract; therefore you won't find any value you can put into method f, until you have a subtype of A which actually fixes T.
(new A { type T = String }).f("bar")
The idea is that the type can be successively refined:
trait Var[A] { def get: A; def set(v: A): Unit }
trait Sys {
type V[A] <: Var[A]
def swap[A](x: V[A], y: V[A]): Unit = {
val tmp = x.get
x.set(y.get)
y.set(tmp)
}
}
trait HistVar[A] extends Var[A] { def created: java.util.Date }
trait HistSys extends Sys {
type V[A] <: HistVar[A]
def newest[A](x: V[A], y: V[A]): A =
if (x.created after y.created) x.get else y.get
}
But of course you're question is good -- there is no reason why you would want a concrete instantiation of a class whose type parameter is not fixed. I can't think of a case where that makes sense. (Well of course, you could still have functionality that is accessible, if it does not involve type T)
Further searching finds the following, quasi duplicate, SO question. You can find there a reference to a Scala ticket which outlines it as a 'feature' -- still doesn't show a case where this 'feature' is actually useful :)

Inheritance and (automatic?) type conversion

Please have a look at the followin code, where Extractor[A,B] is part of a generic framework and everything else should be regarded as "client code" (I boiled it a down quite a bit and renamed everything. So don't mind that Extractor doesn't seem to be too usefull).
scala> abstract class Extractor[A,B] {
| def extract(d:A):B
| def stringRepr(d:A):String
| }
defined class Extractor
scala> sealed abstract class Value
defined class Value
scala> case class IntValue(i:Int) extends Value
defined class IntValue
scala> case class StringValue(s:String) extends Value
defined class StringValue
scala> case class Data(i:Int, s:String)
defined class Data
scala> sealed abstract class MyExtractor[Value] extends Extractor[Data, Value] {
| def stringRepr(d:Data) = extract(d) match {
| case IntValue(i) => i.toString
| case StringValue(s) => s
| }
| }
defined class MyExtractor
scala> class IntExtractor(name:String) extends MyExtractor[IntValue] {
| def extract(d:Data) = IntValue(d.i)
| }
defined class IntExtractor
scala> class StringExtractor(name:String) extends MyExtractor[StringValue] {
| def extract(d:Data) = StringValue(d.s)
| }
defined class StringExtractor
so in short words Extractor[A,B] is used to extract some value B from A and do some other things that are not represented in this show code. The abstract classes Value and MyExtractor are used for reasons of type savety in the "client code".
When I try to create a List of MyExtractors, the following happens:
scala> val l = List.empty[MyExtractor[Value]]
l: List[MyExtractor[Value]] = List()
scala> new IntExtractor("test1") :: l
res5: List[MyExtractor[_ >: IntValue <: Value]] = List(IntExtractor#1fd96c5)
trying to convert an IntExractor to a superclass
scala> new IntExtractor("test"):MyExtractor[Value]
<console>:24: error: type mismatch;
found : IntExtractor
required: MyExtractor[Value]
new IntExtractor("test"):MyExtractor[Value]
^
scala> new IntExtractor("test"):Extractor[Data,Value]
<console>:24: error: type mismatch;
found : IntExtractor
required: Extractor[Data,Value]
new IntExtractor("test"):Extractor[Data,Value]
I am aware that everything is fine, when I define IntExtractor like this
scala> class IntExtractor(name:String) extends MyExtractor[Value] {
| def extract(d:Data) = IntValue(d.i)
| }
defined class IntExtractor
scala> new IntExtractor("test"):Extractor[Data,Value]
res17: Extractor[Data,Value] = IntExtractor#1653d7a
But I don't understand, why it doesn't work the way I tried it above.
I would be thankfull for any help or hints.
As near as I can tell, the concept you are looking for is "covariance". Just because IntValue is a subtype of Value doesn't mean that MyExtractor[IntValue] is a subtype of MyExtractor[Value]. By default, there is no subtyping relation between those two types at all. To create such a relationship, you need to declare MyExtractor to be covariant with respect to it's parameter. Scala lets you declare type parameters to be covariant by adding a "+" before the type parameters declaration. This is called a variance notation.
sealed abstract class MyExtractor[+Value] extends Extractor[Data, Value] {
}
Scala also supports contravariance over type parameters. Contravariance is just like covariance, but reversed, and is expressed with a "-" variance notation on the type parameter. Your Extractor type provides an excellent example of a place where a contravariance notation makes sense.
abstract class Extractor[-A,+B] {
def extract(d:A):B
def stringRepr(d:A):String
}
This means that if Foo is a subtype of Bar, then Extractor[Bar, Baz] is a subtype of Extractor[Foo, Baz], which if you think about it makes sense. If something can extract the data you want when passed an instance of a supertype, then by definition it can extract it when passed an instance of a subtype. Conversely, if Foo is a subtype of Bar, then Extractor[Baz, Foo] is a subtype of Extractor[Baz, Bar]. That also makes sense. If you've got an extractor that returns a Foo, you can certainly use it wherever you need an extractor that returns a Bar.
There are restrictions on when contravariance and covariance can be declared. For instance, contravariant type parameters can only be used as method arguments, and covariant parameters can only be used as method returns or vals. Neither can be used as vars. It gets more complicated with nested type parameters, but the rules basically boil down to "where it's sensible", and your example meets all of them.
Additional side note, all of your abstract classes in your example should probably be declared as traits instead. As long as your abstract classes don't require constructor arguments, declaring them as traits gives you a few more opportunities for reuse.