Scala Covariance and Lower Type Bounds Explanation

前端 未结 4 1145
说谎
说谎 2021-02-02 00:41

I am trying to get my head around covariance in respect with methods creating new immutable types using lower bounds

class ImmutableArray[+T](item: T, existing:          


        
4条回答
  •  清酒与你
    2021-02-02 00:56

    It works because the append method returns a broader class than the original one. Let's conduct a little experiment.

        scala> case class myIntClass(a:Int)
        defined class myIntClass
    
        scala> case class myIntPlusClass(a:Int, b:Int)
        defined class myIntPlusClass
    
       scala> class ImmutableArray[+T](item: T, existing: List[T] = Nil){
             | 
             | private val items = item :: existing
             | 
             | def append[S >: T](value: S) = new ImmutableArray[S](value,items)
             | def getItems = items
             | }
        defined class ImmutableArray
    
        scala> val ia = new ImmutableArray[myIntClass](myIntClass(3))
        ia: ImmutableArray[myIntClass] = ImmutableArray@5aa91edb
    
        scala> ia.getItems
        res15: List[myIntClass] = List(myIntClass(3))
    
        scala> ia.append(myIntPlusClass(3,5))
        res16: ImmutableArray[Product with Serializable] = ImmutableArray@4a35a157
    
        scala> res16.getItems
        res17: List[Product with Serializable] = List(myIntPlusClass(3,5), myIntClass(3))
    
        scala> res16
        res18: ImmutableArray[Product with Serializable] = ImmutableArray@4a35a157
    

    So you can add a derived class here, but it only works due to the fact that the base type of the resulting array is demoted to a lowest common denominator (in this case, Serializable).

    If we try to force the derived type on the resulting array, it won't work:

    scala> ia.append[myIntPlusClass](myIntPlusClass(3,5))
    :23: error: type arguments [myIntPlusClass] do not conform to method append's type parameter bounds [S >: myIntClass]
                  ia.append[myIntPlusClass](myIntPlusClass(3,5))
    

    Trying to do the same making append return an array of derived types won't work, because T is not a subclass of S:

    scala> class ImmutableArray[+T](item: T, existing: List[T] = Nil){
         |           
         |          private val items = item :: existing
         |          
         |          def append[S <: T](value: S) = new ImmutableArray[S](value,items)
         |          def getItems = items
         |          }
    :21: error: type mismatch;
     found   : List[T]
     required: List[S]
                    def append[S <: T](value: S) = new ImmutableArray[S](value,items)
    

提交回复
热议问题