Search code examples
scalagenericspattern-matchingsingleton-type

Do non-type template parameters exist in scala?


Is it possible to have value generics in scala? That is, generics which are not a type but a value. I would imagine them to look something like this: class Animal[legs: Int], but it does not compile.

I have managed to get this to compile but I am not sure the compiler understands it the same way that I do.

abstract sealed class WheeledVehicle(wheels: Int)
case object Motorcycle extends WheeledVehicle(2)
case object Atv extends WheeledVehicle(4)
case object Car extends WheeledVehicle(4)
case object Truck extends WheeledVehicle(6)

Further more, I have not been able to match on a vehicle value.

vehicle match {
    case _: WheeledVehicle(2) => useTwoWheels()
    case _: WheeledVehicle(4) => useFourWheels()
    case _: WheeledVehicle(6) => useSixWheels()
}

Value generics exists in some other languages, such as C++. But what about in scala? And if they do not, is there another way to do what I would like to do?


Solution

  • It seems you just want to define custom unapply

    abstract sealed class WheeledVehicle(val wheels: Int)
    object WheeledVehicle {
      def unapply(arg: WheeledVehicle): Option[Int] = Some(arg.wheels)
    }
    
    vehicle match {
      case WheeledVehicle(2) => useTwoWheels()
      case WheeledVehicle(4) => useFourWheels()
      case WheeledVehicle(6) => useSixWheels()
    }
    

    Motorcycle will match the first pattern, Atv and Car will match the second, Truck will match the third.

    Or

    abstract sealed class WheeledVehicle(val wheels: Int)
    
    vehicle match {
      case w: WheeledVehicle if w.wheels == 2 => useTwoWheels()
      case w: WheeledVehicle if w.wheels == 4 => useFourWheels()
      case w: WheeledVehicle if w.wheels == 6 => useSixWheels()
    }
    

    or

    vehicle match {
      case _ if vehicle.wheels == 2 => useTwoWheels()
      case _ if vehicle.wheels == 4 => useFourWheels()
      case _ if vehicle.wheels == 6 => useSixWheels()
    }
    

    or

    if (vehicle.wheels == 2) useTwoWheels()
    else if (vehicle.wheels == 4) useFourWheels()
    else if (vehicle.wheels == 6) useSixWheels()
    else useDefault()