You are parameterizing the methods with another type parameter A that differs from the one of your class definition. Here's the version you wrote with renamed parameters:
trait HasBuffer[+A] {
var items = Buffer[A]()
def add[B](item: B) = items += item
def remove[B](item: B) { items -= item }
def set(is: Buffer[A]) { items = is }
def clear { items clear }
}
Now it should be clear, why the compiler rejects this.
Instead you can simply write the methods like this:
def add(item: A) = items += item
def remove(item: A) { items -= item }
However, then you will still receive compiler errors stating that covariant type A occurs in contra- and invariant positions.
The point of being covariant is that if you expect a HasBuffer[AnyVal] one may pass in a HasBuffer[Int]. However, if you expect AnyVal and use that type for the add method as well, you would be able to add a completely different type to your HasBuffer[Int]. Hence, the compiler rejects this.
Instead, you will have to provide a lower bound on the type parameter like this:
trait HasBuffer[+A, V <: A] {
var items = Buffer[V]()
def add(item: V) = items += item
def remove(item: V) { items -= item }
def set(is: Buffer[V]) { items = is }
def clear { items clear }
}
With this you may now have methods like the following:
def doSomething[X <: AnyVal](b : HasBuffer[AnyVal, X], e : X) = b.add(e)
This method will work on all sorts of HasBuffer type parameter combinations that satisfy the required lower bound.
Mentally compare this with the idea of not providing a lower bound. Then the method would have become something like this:
// doesn't make much sense!
def doSomething(b : HasBuffer[AnyVal], e : AnyVal) = b.add(e)
If you call this with an object of type HasBuffer[Int] and a Double it'll be all happy. You probably won't be happy lateron though, when you find your buffer that should contain only Ints now contains a Double.