6

For example purposes imagine you have the following:

import play.api.data._
import play.api.data.Forms._
case class TestDomainClass(text: String, number: Int, date: DateTime, long: Long, boolean: Boolean)
val testForm = Form(
  mapping(
    "textField" -> text,
    "numberField" -> number,
    "dateField" -> jodaDate,
    "longField" -> longNumber,
    "booleanField" -> boolean
  )(TestDomainClass.apply)(TestDomainClass.unapply)
)

My objective is to pattern match on the parameter type of each of the fields. For example: for the textField the parameter type would be String, and for the dateField would be org.joda.time.DateTime.


1st Solution attempt

def typeOfMappingUsingTypeTag[T: TypeTag](m: Mapping[T]) = typeOf[T] match {
  case t if t =:= typeOf[String] => println("type is String")
  case t if t =:= typeOf[Int] => println("type is Int")
  case t if t =:= typeOf[org.joda.time.DateTime] => println("type is DateTime")
  case t if t =:= typeOf[Long] => println("type is Long")
  case t if t =:= typeOf[Boolean] => println("type is boolean")
  case _ => println("type is something else")
}
for(m <- testForm.mapping.mappings if m.key.nonEmpty) {
  print(m.key)
  typeOfMappingUsingTypeTag(m)
}

With the following output:

textFieldtype is something else
numberFieldtype is something else
dateFieldtype is something else
longFieldtype is something else
booleanFieldtype is something else

So no luck, which is somewhat expected since in the source the Mapping does not have a context bound to TypeTag.


2nd Solution attempt

def typeOfMappingUsingPatternMatch[T](m: Mapping[T]) = m match {
  case text => println("type is String")
  case number => println("type is Int")
  case jodaTime => println("type is DateTime")
  case longNumber => println("type is Long")
  case boolean => println("type is Boolean")
  case _ => println("type is something else")
}
for(m <- testForm.mapping.mappings if m.key.nonEmpty) {
  print(m.key)
  typeOfMappingUsingPatternMatch(m)
}

With the following output:

textFieldtype is String
numberFieldtype is String
dateFieldtype is String
longFieldtype is String
booleanFieldtype is String

And the following compiling warning:

[warn] /aFolder/aProject/app/controllers/IPBlocks.scala:58: patterns after a variable pattern cannot match (SLS 8.1.1)
[warn]     case text => println("type is String")
[warn]          ^
[warn] /aFolder/aProject/app/controllers/IPBlocks.scala:59: unreachable code due to variable pattern 'text' on line 58
[warn]     case number => println("type is Int")
[warn]                           ^

And the same warning as for the remaining cases.

If I change the order of the cases, whatever case ends up being the first, is the one that gets printed (eg. if case boolean is the first case then the output would be is Boolean for each of the fields)


3rd Solution attempt

Considering the output of:

val t = text
println("t == number " + (t == number))
println("t == text " + (t == text))
println("t eq number " + (t eq number))
println("t eq text " + (t eq text))

is

t == number true
t == text true
t eq number false
t eq text true

Using ifs and eq seems to solve the problem, so I've tried:

def typeOfMappingUsingIfAndEq[T](m: Mapping[T]) = {
  if (m eq text) {
    println("type is String")
  } else if (m eq number) {
    println("type is Int")
  } else if (m eq jodaDate) {
    println("type is DateTime")
  } else if (m eq longNumber) {
    println("type is Long")
  } else if (m eq boolean) {
    println("type is Boolean")
  } else {
    println("type is something else")
  }
}
for(m <- testeForm.mapping.mappings if m.key.nonEmpty) {
  print(m.key)
  typeOfMappingUsingIfAndEq(m)
}

With the following output

textFieldtype is something else
numberFieldtype is something else
dateFieldtype is something else
longFieldtype is something else
booleanFieldtype is something else

So, is there a solution to the problem? If yes, what it is? Also, why in the hell doesn't the 3rd solution work?

Simão Martins
  • 1,210
  • 11
  • 22
  • Maybe reading this post will help you: http://stackoverflow.com/questions/16056645/how-to-pattern-match-on-generic-type-in-scala.. I'm still newbie, but can you try to print the `m` value, using `play.api.Logger.info(m.toString)`.. – Bla... Jul 21 '14 at 16:04
  • What is the actual usecase? I have the feeling that the actual problem should be solved differently. – EECOLOR Jul 22 '14 at 20:59
  • @EECOLOR I'm trying to implement a generic CRUD module. This will solve the problem of what type of input to create given the user defined form. – Simão Martins Jul 23 '14 at 23:52
  • Can you update the question with your intended use case (code that shows how you want to use this)? – EECOLOR Jul 24 '14 at 15:13
  • @user26409021 Sorry for the delay the output is: [info] application - FieldMapping(textField,List()) [info] application - FieldMapping(numberField,List()) [info] application - FieldMapping(dateField,List()) [info] application - FieldMapping(longField,List()) [info] application - FieldMapping(booleanField,List()) – Simão Martins Jul 29 '14 at 23:00
  • Instead of using the `String`, try using `List[String]`. Because from what I see your `m` variable doesn't return only the data-type. – Bla... Jul 30 '14 at 04:30

1 Answers1

0

I'm not sure if I understood exactly what you are after, but if you want to do stuff based on an object type you could use pattern matching this way:

value match {
    case stringValue : String => // value es a String! You can use the stringValue variable which's type is String but reference the same object
    case intValue : Int => // value is an Int. Do stuff.
    ...
    case _ => // any other case
}

Regarding your third implementation beware about the use of eq. Eq checks for identity, which is not the same idea as equalty. (You can check this post for more info). Plus, as your code is taken out of context i'm not sure how are some of those variables defined, but if, for example, we take these lines:

def typeOfMappingUsingIfAndEq[T](m: Mapping[T]) = {
    if (m eq text) {
    ...

If your text variable's type is String (as it is on TestDomainClass), there is no way it will be equal/identical to m, wich is of type Mapping[T]).

Hope this helps!

Good luck!

Community
  • 1
  • 1