I have an enum for keywords and operators (and some other too), e.g. (all are similar):
object Keywords extends Enumeration {
val AND, ARRAY, BEGIN, ...= Value
case class Keyword(keyword: Value) extends Token[Value] {
def this(keyword: String) = this(Keywords.fromString(keyword))
def value = keyword
}
implicit def valueToKeyword(keyword: Value) = new Keyword(keyword)
}
this implicit conversion allows me to pass enum values where Tokens are expected e.g.
def testFunction[T](t: Token[T]) = ...
testFunction(Keywords.ARRAY) // gets converted
testFunction(Operators.PLUS) // gets converted too
it also seems that the same implicit conversion is not applied during matching i.e.
val token = new Keyword("ARRAY")
token match {
case Keywords.ARRAY => ... // not selected but SHOULD be
case Operators.PLUS => ... // completely different Enum
...
}
Why? How to overcome this?
This doesn't work because:
token match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
is essentially a PartialFunction with the following type signature: PartialFunction[Keywords.Value, Unit]. Which means an implicit won't be applied, because it's either isDefinedAt or it isn't for that input.
If it isn't defined than case _ => ... will catch everything in my example code. If it's not defined at all and nothing will match it then you will get a MatchError thrown.
In your case token of type Token[Value] isn't defined in the Partial Function that the match will compile to, because only types of Keywords.Value are defined.
Three solutions
If you really want implicits then you could explicitly ask for an implicit (yes, that sentence is funny :))
implicitly[Keywords.Value](token) match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
Or you can explicitly state the type of token, to invoke the implicit magic:
val token: Keywords.Value = new Keyword("ARRAY")
token match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
Or the simplest solution if you can live without implicits:
token.value match {
case Keywords.ARRAY => println("Array")
case _ => println("Something else")
}
I know it's not the answer you're looking for, but I hope that you understood what match {...} really means and what Partial Functions are.
Related
I am writing an implicit reads returning JsResult[Seq[T]] based on a condition:
some_condition match{
case Some(value) => // JsResult[Seq[T]]
case _ => // returning an empty JsResult here of similar type?
}
What would be the way for return such JsResult?
You will need to use the method validate, which returns JsResult. There are 2 case classes that inherits JsResult:
JsSuccess
JsError
Therefore you can consider the following example:
case class T()
implicit val reads = Json.reads[T]
val jsValue: JsValue = ...
jsValue.validate[Seq[T]] match {
case JsSuccess(t, path) =>
println(t)
case JsError(errors) =>
println(errors)
}
How can rewrite the following to make it more 'Scala way' or use just one match?
case class Foo(bar: Any)
val fooOpt = Some(Foo("bar as String"))
def isValid(p: Any) = p match {
case _ # (_: String | _: Int) => true
case _ => false
}
//Is it possible to check for the type of bar directly in this if statement?
fooOpt match {
case Some(f) if isValid(f.bar) => doSomething
case _ => doSomethingElse
}
One alternative would be using the isInstanceOf.
fooOpt match {
case Some(f) if f.bar.isInstanceOf[String] => doSomething
case Some(f) if f.bar.isInstanceOf[Int] => doSomething //could also rewrite to use just one case
case _ => doSomethingElse
}
Is there other way?
This can all be done in one big pattern match:
fooOpt match {
case Some(Foo(_: Int | _: String)) => doSomething
case _ => doSomethingElse
}
If you want to get the Int or String out, just split that case:
fooOpt match {
case Some(Foo(i: Int)) => doSomething
case Some(Foo(s: String)) => doSomething
case _ => doSomethingElse
}
Is there other way?
Although the solution with one big patten match works(and can be used if you really can't change bar to anything more specific than Any), it is not a proper 'Scala way' of dealing with this situations in general if you have control over Foo.
A better way would be to make Foo generic:
case class Foo[T](bar: T)
And have either a generic doSomething, if it can work with any particular T:
def doSomething[T](foo: Foo[T]): SomeType = ???
or to have different versions of it for different possible T's you have, if it should react on them differently:
def doSomethingWithString(foo: Foo[String]): SomeType = ???
def doSomethingWithInt(foo: Foo[Int]): SomeType = ???
Then you can use it just like this:
val fooOpt = Some(Foo("bar as String"))
fooOpt.map(doSomething).orElse(doSomethingElse)
or like this:
val fooOptString = Some(Foo("bar as String"))
fooOptString.map(doSomethingWithString).orElse(doSomethingElse)
val fooOptInt = Some(Foo(1))
fooOptInt.map(doSomethingWithInt).orElse(doSomethingElse)
So, in this case compiler checks types for you, answering to:
Is it possible to check for the type of bar directly?
And in many situations you can avoid using pattern match at all, using methods like map, orElse, etc. with proper typing. This might be an answer for this:
could also rewrite to use just one case
I have a toy function defined as follows:
case class Foo (a : Int, b : String)
def get(): Either[String, Future[Option[Foo]]] = {
Right(Future.successful(Some(Foo(1, "ABS"))))
}
In the Scala Play controller, I attempt to pattern match on the result of this function call:
def hello() : Action[AnyContent] = Action.async { implicit request =>
get() match {
case Right(x) => x.map{
case foo => Ok(Json.toJson(foo))
case None => NoContent
}
case Left(x) => InternalServerError(x)
}
}
The problem is the last Left case statement. If I omit it, then everything type checks. But as soon as I add that Left case statement to handle the error condition, it breaks as the code does not type check anymore. What am I doing wrong here?
You are not returning a Future from your left case, and your InternalServerError wont be automatically wrapped, so you have to do this way:
case Left(x) => Future.successful(InternalServerError(x))
I am porting a class from Ruby to Scala 2.11 that implements variable merging in messages. I would like to pass an array of objects to the merge method and have it search each object for the keys that are referenced in the text of the message.
The core of this is a method called lookUp(key: String, obj: AnyRef) which receives a single key for which to search, and a single object on which to search for the key. If the object is a Map, and the Map's keys are either Symbol or String, then it will look in the Map for the requested key. Otherwise it will check if the object has a method with the same name of the key, and if so, it will invoke that method.
In the existing Ruby code, it is trivially easy to do this:
def look_up(key, obj)
if obj.respond_to?(:has_key?) && obj.has_key?(key)
obj[key]
elsif obj.respond_to?(key)
obj.send(key)
elsif obj.instance_variable_defined?(ivar = "##{key}")
obj.instance_variable_get(ivar)
end
end
Since it's easy to do so, the Ruby code also looks for an instance variable of the same name. I don't necessarily need that functionality in my Scala version.
One of the issues I am having is that the examples I've found require that I know the object's class ahead of time so I can call ru.typeOf[MyClass].declaration(ru.TermName("key")) (where ru is scala.reflect.runtime.universe).
Another issue is that this message merge can be happening hundreds of times per minute, and reflection seems to be a slow, involved process. If this all works as planned, I'll likely cache the reflection results by object type.
UPDATE: I was thinking about something like this, but is this overkill? Or is it necessary to properly capture the types in the Map? Also, this doesn't compile. Map, Symbol and String aren't the right types for their context.
def lookUp[T](obj: T, key: String)(implicit tag: ru.TypeTag[T]): Option[String] = tag.tpe match {
case ru.TypeRef(a, Map, List(Symbol, _)) => if (obj.contains(Symbol(key))) Some(obj(Symbol(key)).toString) else None
case ru.TypeRef(a, Map, List(String, _)) => if (obj.contains(key)) Some(obj(key).toString) else None
case _ =>
if (/* obj.key() exists */)
// Some(obj.key().toString)
else
None
}
UPDATE 2: It never occurred to me that I could use asInstanceOf with something like Map[String, _]. I used #johny's second example of code to come up with my solution. I cache the method names by class in a mutable.HashMap[Class[_], Set[String]].
def lookUp(obj: AnyRef, key: String): Option[String] = obj match {
case m: Map[_, _] =>
if (m.asInstanceOf[Map[String, _]].contains(key))
extractValue(m.asInstanceOf[Map[String, _]](key))
else if (m.asInstanceOf[Map[Symbol, _]].contains(Symbol(key)))
extractValue(m.asInstanceOf[Map[Symbol, _]](Symbol(key)))
else
None
case _ =>
val klass = obj.getClass
if (!methodsCache.contains(klass))
methodsCache(klass) = klass.getMethods.toList.filter(_.getParameterCount == 0).map(_.getName).toSet
val methodNames = methodsCache(klass)
if (methodsCache(klass).contains(key))
extractValue(klass.getDeclaredMethod(key).invoke(obj))
else
None
}
def extractValue(obj: Any): Option[String] = obj match {
case null | None => None
case Some(x) => Some(x.toString)
case x => Some(x.toString)
}
def lookUp(key: String, obj: AnyRef) {
obj match {
case x: Map[String, _] => x(key)
case _ => obj.getClass.getDeclaredMethod(key).invoke(obj)
}
}
Edit: To make sure key of Map is either String or scala.Symbol
def lookUp(key: String, obj: AnyRef)= {
obj match {
case x: Map[_, _] =>
if(x.asInstanceOf[Map[String,_]].contains(key))
x.asInstanceOf[Map[String,_]].get(key)
else if(x.asInstanceOf[Map[scala.Symbol,_]].contains(scala.Symbol(key)))
x.asInstanceOf[Map[scala.Symbol,_]].get(scala.Symbol(key))
else
None
case _ => Some(obj.getClass.getDeclaredMethod(key).invoke(obj))
}
}
The above too doesnt make sure the returned output is from the intended Map.
Edit: Following #JimCain's lead
def lookUp[T:ru.TypeTag](obj: T, key: String): Option[Any] = ru.typeTag[T].tpe match {
case ru.TypeRef(a, m, l) if(m.name.toString=="Map"&&l.head =:= ru.typeOf[java.lang.String])=> obj.asInstanceOf[Map[String,_]].get(key)
case ru.TypeRef(a, m,l) if(m.name.toString=="Map"&&l.head =:= ru.typeOf[Symbol])=> obj.asInstanceOf[Map[Symbol,_]].get(scala.Symbol(key))
case _ => Try(obj.getClass.getDeclaredMethod(key).invoke(obj)) match {
case Success(x) => Some(x)
case Failure(_) => None
}
}
How would you implement class that parses some input via regex and transforms founded string to some other type? My approach is:
class ARegex[T](regex:Regex, reform:Option[String => T]){
def findFirst(input:String):Option[T] = {
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s) // this won't compile because of type mismatch
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
class BRegex[T](regex:Regex, reform:Option[String => T]) {
def findFirst(input:String) = { //returns Option[Any] - erasure
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s)
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
We can solve this problem by eliminating the Option part of the reform's type, and using a different mechanism to indicate that we don't want to change the match in any way. This mechanism is to use identity as a default parameter or pass identity when you don't want the type to change.
class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
def findFirst(input:String):Option[T] = {
regex.findFirstIn(input) match{
case None => None
case Some(s) => Some(reform(s))
}
}
}
new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]
Well, the problem is the type mismatch, because you are returning either a String or a T, which, of course, are unified at Any. You can't say you are going to return Option[T] and then return Option[String].
Other than that, a simplified version of that code is this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Any] =
regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}
You could return an Option[Either[String, T]], though. The code would look like this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Either[String, T]] =
regex findFirstIn input map { s => reform map (_(s)) toRight s }
}
Why is reform Option[String => T] instead of just String => T? If you don't pass in a mechanism for creating an instance of your desired type, there's no mechanism for the runtime system to actually create the appropriate object. If you really need to pass in an Option[String => T] then your second case should simply return None.
Also, flatMap is your friend, and will give you the correct behavior (i.e. if reform is None, the method returns None.
class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
}