0

I am trying to use pattern matching on a List of objects. The method takes in queue: List[ScheduleChangeEvent]. ScheduleChangeEvent is a sealed trait with 4 different final case class's. Therefore, depending on what type of ScheduleChangeEvent the list contains, I need to do something different.

I implemented the following:

queue match {

      case lsc: List[LocationSettingsChange] =>
        ...
      case lwhc: List[LocationWorkHoursChange] =>
        ...
      case tpc: List[TeamParameterChange] =>
        ...
      case mptc: List[MemberPrimaryTeamChange] =>
        ... 
    }

However, I get the warning unreachable code [warn] case tpc: List[LocationWorkHoursChange] =>. And no matter what the incoming queue is, it always goes to case lac. I understand what the warning is, but I cannot understand why I am getting it.

TreyBCollier
  • 213
  • 3
  • 8
  • 3
    You are hitting type erasure, what you want to do is not easy to accomplish and in general unsafe. You may pattern match on each element of the list. – Luis Miguel Mejía Suárez Sep 16 '21 at 15:54
  • Yeah, I did also get that erasure warning. Problem is I need the whole queue really, and what makes it unsafe? Thanks for the reply. @LuisMiguelMejíaSuárez – TreyBCollier Sep 16 '21 at 15:57
  • You can't really check at runtime that the `List` only has some subtypes in an easy fast and safe way, although I believe **Shapeless** does provide that function. Anyways, you may try to check that all elements of the list are a specific instance of your ADT, but that will be slow and somehow unsafe, or even better create a wrapper ADT for your queues. Check this: https://scastie.scala-lang.org/BalmungSan/FUVXpbeuR7eqMxgB1887rw/4 – Luis Miguel Mejía Suárez Sep 16 '21 at 16:42

1 Answers1

0

This is because in runtime you have erasure. This means that jvm don't have type parameter values for generics. I.e. instead of List[LocationSettingsChange] or List[LocationWorkHoursChange] you have just List in runtime. thing you can do with non-empty list is an introspection of kind case head :: tail if head.isInstanceOf[LocationSettingsChange] or with extractor if you have one. Generally try to avoid situations where you should do this, and if you can do something like that by passing pattern matching from list to element of list:

list.map { 
  case x: LocationSettingsChange => ???
  case x: LocationWorkHoursChange=> ???
  case x: TeamParameterChange=> ???
  case x: MemberPrimaryTeamChange=> ???
}

By doing this you won't have any problems with erasure, but if you still need this you can use type tags and match on them at cost of runtime performance penalty, more of this described here: https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html

Iva Kam
  • 932
  • 4
  • 13