Reputation: 7
I have below code:
trait Vehicle {
def regNumber: String
def lotSize: Int
}
case class Car(regNumber: String) extends Vehicle {override val lotSize = 2}
case class Motorcycle(regNumber: String) extends Vehicle {override val lotSize = 1}
trait AbstractLot[+T <: Vehicle] {
def vehicle: T
def lotSize: Int = vehicle.lotSize
}
final case class CarLot(vehicle: Car) extends AbstractLot[Car]
final case class MotorcycleLot(vehicle: Motorcycle) extends AbstractLot[Motorcycle]
I want to have a ParkingLot
type which is an array of option of abstract lot. But, Scala compiler is not happy when I wrote below code
object ParkingLot {
type ParkingLot = Array[Option[AbstractLot[_]]]
//Case 1: OK
def mixMotorcycleCar(motorcycleCapacity: Int, carCapacity: Int): ParkingLot =
Array.fill[Option[MotorcycleLot]](motorcycleCapacity)(None) +: Array.fill[Option[CarLot]](carCapacity)(None)
//Case 2: Not OK
//T is a subclass of AbstractLot. Why isn't this working?
def homogenous[T <: AbstractLot[_]](capacity: Int): ParkingLot = Array.fill[Option[T]](capacity)(None)
//Case 3: Not OK
def carOnly(capacity: Int): ParkingLot = Array.fill[Option[CarLot]](capacity)(None)
}
What did I do wrong? And how should I fix my code so that I can have a ParkingLot
type that works in Case 2 and Case 3?
Upvotes: 0
Views: 72
Reputation: 838
The problem here is that mutable collections have invariant element types in Scala so you can't store Option[CarLot]
nor Option[MotorcycleLot]
elements in Array[Option[AbstractLot[Any]]]
. The reason for this can be found here: relation between variance and mutabilty / immutability in Scala.
ParkingLot object is used mainly for space preallocation which is rarely needed in Scala. You have to rethink your design because it won't be possible to create any mutable collection with covariant type. The simplest way to represent a parking lot using a mutable collection would be something like this:
val parkingLot = ArrayBuffer[Vehicle]()
parkingLot.addOne(Car("123"))
parkingLot.addOne(Motorcycle("321"))
Upvotes: 1