Maths noob
Maths noob

Reputation: 1802

Scala: Pattern matching a generic case class for "concrete" cases

let's say I have:

sealed trait Data
final case class TextData()  extends Data
final case class ImageData() extends Data
final case class MetaData[D <: Data](data: D) extends Data

I want to pattern match Data objects. I have defined:

def getDataTypeName(data: Data): String ={
    data match {
        case TextData()=>"text"
        case ImageData()=>"image"
        //MetaData(MetaData(_))=>"metaMeta1"  //a
        case _:MetaData[MetaData[_]]=>"metaMeta2"  //b
        //case MetaData(data:Data)=>"meta"+ getDataTypeName(data) //c
        //MetaData(TextData(_))=>"metaMeta1"  //d
        case MetaData(_)=>"meta"
    }
}

I want to be able to see if my data is a meta-metadata, meta-TextData, etc. Line a give me an error, saying:

constructor cannot be instantiated to expected type; found : inst$A$A.MetaData[D] required: A$A115.this.Data case MetaData(MetaData(_))=>"metaMeta1"

I would prefer to have something resembling line a. alternatively something like line c would be nice too.

I also tried line b. This one generates some warnings:

non-variable type argument A$A115.this.MetaData[] in type pattern A$A115.this.MetaData[A$A115.this.MetaData[]] is unchecked since it is eliminated by erasure case :MetaData[MetaData[]]=>"metaMeta" ^

I get this warning for both MetaData[_]s. My understanding is that the said pattern is reduced to _ after type erasure which is consistent with my test results.

I therefore want to know if there is a way of matching against MetaMetaData, MetaTextData ,MetaMetaMetaData etc.

Alternatively, is my design using sealed class in a way they shouldn't be used? What alternative design would you suggest?

Upvotes: 1

Views: 1290

Answers (2)

pedrorijo91
pedrorijo91

Reputation: 7845

  sealed trait Data
  final case class TextData()  extends Data
  final case class ImageData() extends Data
  final case class MetaData[D <: Data](data: D) extends Data

and

def getDataTypeName(data: Data): String ={
    data match {
      case TextData()=>"text"
      case ImageData()=>"image"
      case MetaData(MetaData(_))=> "metaMeta1" 
      case MetaData(TextData())=> "textMeta1"  
      case MetaData(ImageData())=> "imgMeta1"  
    }
  }

testing on REPL:

scala> getDataTypeName(TextData())
res1: String = text

scala> getDataTypeName(MetaData(TextData()))
res2: String = textMeta1

scala> getDataTypeName(MetaData(MetaData(TextData())))
res3: String = metaMeta1

Upvotes: 0

jwvh
jwvh

Reputation: 51271

I made a change to the MetaData() definition to make this work.

sealed trait Data
final case class TextData()  extends Data
final case class ImageData() extends Data
final case class MetaData(data: Data) extends Data

def printType(data: Data): String = data match {
  case TextData()=>"text"
  case ImageData()=>"image"
  case MetaData(d)=>"meta:" + printType(d)
}

val md = MetaData( MetaData(TextData()) )
printType(md)  // res0: String = meta:meta:text

Upvotes: 3

Related Questions