1

This a very simple scala sample, but it can't be compiled:

abstract class Box[+A] {
    var value: A = _
}

The error is:

covariant type A occurs in contravariant position in type A of parameter of setter value_=

What I want the class to do is:

class StringBox extends Box[String]
class DateBox extends Box[Date]

object Testbox {
    def main(args: Array[String]) {
        val list = ListBuffer[Box[Any]]()
        val str = new StringBox
        str.value = "abc"
        val date = new DateBox
        date.value = new Date
        list += str
        list += date
        println(list)
    }
}
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
Freewind
  • 193,756
  • 157
  • 432
  • 708
  • 1
    What would happen if you added this code: `list[1].value = "fail"`? "fail" is an `Any`, and list is a `ListBuffer[Box[Any]]` so that should be valid. But then, the element in the list is a `Box[Date]`. Ooops, we just assigned a string to a date! – R. Martinho Fernandes Mar 18 '11 at 11:55

3 Answers3

4

Mutable classes (and your class Box is mutable) cannot be covariant in the type of their mutable field. You can make Box immutable though

abstract class Box[+A] { val value: A }
Michael
  • 10,185
  • 12
  • 59
  • 110
4

It does not compile because it is incorrect. If scala were to allow you to do it, then you could violate type safety. For example:

import scala.annotation.unchecked.uncheckedVariance

abstract class Box[+A] {
    var value: A  @uncheckedVariance = _
}

class StringBox extends Box[String]
val sb = new StringBox; sb.value = "abc"
val sa: Box[Any] = sb
sa.value = 5
println(sb.value.length)
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 1
    @Daniel Thank you for the answer. I did not know about @uncheckedVariance – Michael Mar 18 '11 at 12:22
  • 2
    @Misha You shouldn't use it, though. If Scala tells you something is wrong, then something is most likely wrong. – Daniel C. Sobral Mar 18 '11 at 13:41
  • @Daniel, could you give me a correct sample which I can set values to `StringBox` and `DateBox`? – Freewind Mar 18 '11 at 15:24
  • @Freewind I don't understand what do you mean by "correct". The code here is compilable, and you can replace `5` with a `new Date` just as well. – Daniel C. Sobral Mar 18 '11 at 17:54
  • I mean, is it possible not use `@uncheckedVariance`, but let `Box` do the same thing? – Freewind Mar 19 '11 at 01:36
  • @Freewind There are ways to get around variance, but this is one specific example of what is precisely what shouldn't and can't be done. If you want to expose `value` as a `var` to be used outside the class, then it cannot be covariant. – Daniel C. Sobral Mar 20 '11 at 00:10
2

Please see the answer to this question: Scala covariance / contravariance question

Community
  • 1
  • 1
Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171
  • thank you, I have read that, but that does not resolve my problem: I need to set values, so I can't use `val` – Freewind Mar 18 '11 at 15:24