Reputation: 149
class Queue[+T](
private val leading: List[T],
private val trailing: List[T]
) {
def append[U >: T](x: U) =
new Queue[U](leading, x :: trailing) // ...
}
class Fruit
class oranges extends Fruit
class apple extends Fruit
class diffAppale
val q1: Queue[Fruit] = new Queue[apple](List(new apple), List())
//> q1 : Test.Queue[Test.Fruit] = Test$Queue@30c7da1e
q1.append(new Fruit)
//> res0: Test.Queue[Test.Fruit] = Test$Queue@506e6d5e
q1.append(new oranges)
//> res1: Test.Queue[Test.Fruit] = Test$Queue@96532d6
q1.append(new diffAppale) // i want to restrict this
//> res2: Test.Queue[Object] = Test$Queue@3796751b
Here i could add to append function what ever object i can , i can see the resulting type is is demoted to a lowest common denominator
But i would like to have same behaviour as java, say def append[? super T](x: U) // here append function will take all objects which are supertype of T ,How can i achieve similar one in scala (implement super and extend for generics like java)
Upvotes: 2
Views: 854
Reputation: 67280
I don't understand why you want to restrict this or why returning a more generic new immutable object poses a problem for you.
But if you don't want that variance, simply remove all the variance annotations:
class Queue[A](leading: List[A], trailing: List[A]) {
def append(x: A) = new Queue[A](leading, x :: trailing) // ...
}
class Fruit
class Orange extends Fruit
class Apple extends Fruit
class NotFruit
val q1: Queue[Fruit] = new Queue(List(new Apple), Nil)
val q2 = q1.append(new Fruit) // ok
val q3 = q2.append(new Orange) // ok
q1.append(new NotFruit) // error - found NotFruit, required Fruit
As to the question:
append function will take all objects which are supertype of T
This is what your original code already does. Note that Any
is super-type of all types. Since the argument is in covariant position, it is always possible to pass a value with a sub-type of Any
for an argument of expected type Any
. That's life :) Scala just feels different than Java because it is built around declaration site variance and not use site variance (arguably a better decision than Java's generics).
If you want further constraints, you can ask for an evidence parameter such as
def append[B >: A](x: B)(implicit ev: B <:< Seedless): Queue[B]
Or put an upper bound (this cannot be the same as A
because of A
's variance):
def append[B >: A <: Fruit](x: B): Queue[B]
But: it really doesn't make sense IMHO.
Upvotes: 1