I've got the following models:
case class Questionnaire(List(Question[_])
case class Question[A](text: String, Answer[A])
case class Answer[A](value: A)
I'm trying to set all of the answers on a questionnaire depending on their type (answers can be of type String, Double or LocalDate):
val questionnaire = getMockQuestionnaireWithoutAnswers()
questionnaire.questions.map {
case x: Question[String] => //...default the answer.value to some random string
case x: Question[Double] => //...default the answer.value to some random double
case x: Question[LocalDate] => //...default the answer.value to some random date
}
But I'm getting the error:
non-variable type argument String in type pattern examplenamespace.Question[String] is unchecked since it is eliminated by erasure.
I don't want to wrap all of the types into classes like this:
case class StringQuestion(question: Question[String])
What is the best way to avoid this error?
Type erasure is eliminating the parametric type provided in the match expression, meaning that the difference between Question[String]
and Question[Int]
gets lost at runtime.
One way to circumvent this is to provide concrete implementations of that type, sothat the JVM cannot "erase" it.
I've used this construction in the past. There're probably other ways, but this one is simple enough:
case class Answer[A](a:A)
case class Question[A](text: String, answer: Answer[A])
case class Questionnaire(questions: List[Question[_]])
// concrete types
trait StringQuestion extends Question[String]
trait DoubleQuestion extends Question[Double]
trait IntQuestion extends Question[Int]
def resolve(questions: List[Question[_]]): List[String] = {
questions.map {
case x: StringQuestion => "Stringy"
case x: DoubleQuestion => "Doubly"
case x: IntQuestion => "Inty"
}
}
Try this approach:
questionnaire.questions.map {
case Question(text, Answer(d:Double)) => //
case Question(text, Answer(s:String)) => //
case Question(text, Answer(ld:LocalDate)) => //
}
You have access to text of Question (text) and value of Answer (d, s or ld)
You also can use aliases for variables:
questionnaire.questions.map {
case q @ Question(text, a @ Answer(d:Double)) => //
case q @ Question(text, a @ Answer(s:String)) => //
case q @ Question(text, a @ Answer(ld:LocalDate)) => //
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With