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))
Related
I have async Play Action, that retrieves data from the datbase, using Slick. And Slick, obviously, uses Futures to avoid blocking:
def show(id: Long) = Action.async {
db.run(entities.filter(_.id === id).result.headOption).map {
case None => templateFor("NEW_OBJECT")
case Some(x) => Ok(x)
}
def templateFor(code: String): Future[Result] = {
db.run(templates.filter(_.code === code).result.headOption).map {
case None => InternalServerError("No template")
case Some(x) => Ok(x)
}
}
The problem is that call to templateFor() returns Future, so the whole Action returns Future[Future[Result]] which is not what expected by Play. So, i would like to get rid of that nested Future. The simple way to do it is to Await for it's completion, but i would like to avoid unnecessary blocking. It would be nice if i would be able to take Future[Result] produced by templateFor() function and return it intact from my Action, thus replacing the outer Future with it.
You can use flatMap for that,
For any monandic strutcture such as Future[T], flatMap takes a function of type T => SomeOtherMonad[K], applies that function on all elements if monad and then flattens them to gives you Future[K].
def show(id: Long) = Action.async {
db.run(entities.filter(_.id === id).result.headOption).flatMap {
case None => templateFor("NEW_OBJECT")
case Some(x) => Future(Ok(x))
}
def templateFor(code: String): Future[Result] =
db.run(templates.filter(_.code === code).result.headOption).map {
case None => InternalServerError("No template")
case Some(x) => Ok(x)
}
}
There are quite a few questions about this error message on SO, but none of them seem to be about this issue.
The argument types of an anonymous function must be fully known. (SLS 8.5)
The offending block of code is attempting to emulate Ruby's block functionality, with the added benefit that an argument can be pattern matched in the process.
object Block {
def apply(f: => Unit) = apply((_: String) => f)
def apply(f: String => Unit) = ???
}
def example() = {
Block { // Error!
case "A" => println("First letter of the alphabet")
case _ => println("Not the first letter of the alphabet")
}
}
Even though, one line down, Scala can clearly see that I'm matching against a string, it can't infer the argument type.
The trouble here is that there are two apply methods. If there was only one:
object Block {
def apply(f: String => Bool) = ???
}
Then everything would work fine, as Scala would see the application and immediately understand the required type of the anonymous function. However, when there are two or more different methods:
object Block {
def apply(f: => Bool) = apply((_: String) => f)
def apply(f: String => Bool) = ???
}
Scala cannot deduce the type of the argument from the application of apply, and it cannot deduce which application of apply to use from the type of the argument, so it gets caught in a loop. The simplest solution, it seems, is to simply rename one of the methods.
object Block {
def apply(f: => Unit) = apply((_: String) => f)
def branchOff(f: String => Unit) = ???
}
It's not much more difficult to call now.
Block { println("This is a regular application.") }
Block.branchOff {
case "A" => println("A is for aardvark")
case "B" => println("B is for beaver")
case _ => println("Huh?")
}
And you don't have to specify any type arguments, or any explicit arguments at all for that matter.
More details on this in a thread over on GitHub: https://github.com/ReactiveX/RxScala/issues/160.
If you really like the idea of having two different apply() methods then you have to offer some help to the inference engine.
def example() = {
Block{s:String => s match {
case "A" => println("First letter of the alphabet")
case _ => println("Not the first letter of the alphabet")
}}
}
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 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
}
}
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.