I have a case match statement that provides the following output. I'm trying to convert this into a sequence instead. Can you please help me with this?
java.io.Serializable = List(TableInfo(X,XX,List(aa#aa.com, bb#bb.com)),
TableInfo(Y,YY,List(aa#aa.com, bb#bb.com)))
[Code]:
scala.util.Either[Exception,List[TableInfo]] =
Right(List(TableInfo(X,XX,List(aa#aa.com, bb#bb.com)),
TableInfo(Y,YY,List(aa#aa.com, bb#bb.com))))
result match {
case Left(s) => s
case Right(i) => i
}
Complete Code: https://scastie.scala-lang.org/HT8wmYtsRF6DwzEkJYeygA
Your code doesn't throw any exceptions right now. Based on the comments, it sounds like your intention is to extract a Right or throw whatever's on the Left. In that case, all you're missing is the throw keyword.
result match {
case Left(s) => throw s
case Right(i) => i
}
throw breaks the normal flow of control, so it returns Nothing, which is the unique subtype of all types in Scala. Thus, the common types of Nothing and whatever s is, is simply the type of s.
Related
I was tinkering with Try, per this:
val files = Stream("a.txt", "b.txt", "c.txt")
files
.map(s => Try(Source.fromFile(s)))
.flatMap(t => t match {
case Failure(x) =>
Console.err.println(s"Failure: x.getMessage")
Stream.Empty
case Success(s) => Stream(s)
})
.flatMap(t => t.getLines.toStream)
.foreach(println)
and while it works, exactly as I hoped/intended, I was left with an uneasy feeling that I could not identify exactly how the "Source.fromFile(s)" part actually gets evaluated. the argument to the Try.apply method is documented as a by-name parameter, so clearly something must force evaluation of that.
But, it seems to me that the very next operation would be the "t match" part, and that's looking at the type of object that the Try.apply created, and that can't work if the object hasn't been created, and it can't be created without evaluating the argument to apply. In which case, I don't see any point the argument being in the first place.
Or, perhaps there's something intrinsically lazy about the behavior of case classes? Or maybe I'm just missing something obvious.
Would someone mind clarifying this for me?
The part you are missing is that the argument to Try has to be by-name so that exceptions thrown by that computation can be caught and reified as Failures. Otherwise the argument would be evaluated before Try has had a chance to catch anything which would defeat the purpose. You can even look at the source code of Try.apply which is very simple. It immediately forces its argument:
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
Suppose I have many akka services which all return a case class of type AbcDto wrapped in a Try.
So I call all these services using map and get back a List[Future[Any]].
Now I use Future.sequence to convert this to Future[List[Any]].
How do I unwrap my final list of results? I want to process them only when all of them are a Success and even if one fails I want to throw an error.
I tried mapping Future[List[Any]] as:
val a: List[Future[Any]]
a.map {
case r: List[Success[AbcDto]] => println("hello")
}
But this gives error:
case r: List[Try[AbcDto]]. At this point its giving error: non-variable type argument scala.util.Try[AbcDto] in type pattern List[scala.util.Try[AbcDto]] (the underlying of List[scala.util.Try[AbcDto]])
since all akka services return AbcDtowrapped in a Try the proper type of val a should be List[Future[Try[AbcDto]]]. Now the desired result can be achieved by a combination of Future.sequence and flatMap operation to check for any Failures in the service as shown below.
val a: List[Future[Try[AbcDto]]] = ...
val result: Future[List[AbcDto]] = Future.sequence(a) flatMap {
case r: List[Try[AbcDto]] #unchecked if r.find(!_.isSuccess).isDefined => Future.failed(new RuntimeException("not all results are successful"))
case r => Future.successful(r.collect({ case Success(x) => x}))
}
Future[A] and Try[A] in the actor context are so similar that I see no point to return Try[A] from those actors. You just return A in case of success, which will be Future[A] on asking side, a List of which you can sequence and get Future[List[A]], which, in case of a single failure, will contain the first encountered exception. It seems to be exactly what you're asking for.
To communicate failure from an actor to the asker, you should send akka.actor.Status.Failure with the relevant instance of Throwable.
P.S. regarding comment that using try-catch is non-idiomatic Scala. It actually is. Here's how Try creation is implemented:
object Try {
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
}
As you can see, it uses try-catch inside. If Scala standard library authors are fine with that, so should be you. :)
If I understand you correctly (the types in your question are a bit confusing),
You start with a val responseFutures: List[Future[Any]] and after conversion you have a val responsesFuture: Future[List[Any]]. rogue-ones answer is correct, but it could use some clarification:
Your compiler error is caused by the fact that Success is not a class, but an extractor object with unapply for Try. Therefore you cannot use in in type extraction this way.
So something like case r: List[Try[AbcDto]] if r.forall(_.isSuccess) => println("hello") should compile. However, as AbcDto is erased, you will get a compiler warning about erasure. Thus the #unchecked.
UPDATE
Type erasure means, the compiler cannot check type argument type in pattern matches at compile time. In your case, all the compile knows of your input type is Future[List[Try[Any]]].
So
future.map {
case _: List[Try[AbcDto]] => ???
}
will cause a compiler warning because the compiler only sees.
future.map {
case _: List[Try[_]] => ???
}
The #unchecked annotation just suppresses the corresponding compiler warning.
In the end with the pattern match above you just cast whatever is coming in to Try[AbcDto] without any compile time type safety.
I'm starting to learn the great Scala language ang have a question about "deep" pattern matching
I have a simple Request class:
case class Request(method: String, path: String, version: String) {}
And a function, that tries to match an request instance and build a corresponding response:
def guessResponse(requestOrNone: Option[Request]): Response = {
requestOrNone match {
case Some(Request("GET", path, _)) => Response.streamFromPath(path)
case Some(Request(_, _, _)) => new Response(405, "Method Not Allowed", requestOrNone.get)
case None => new Response(400, "Bad Request")
}
}
See, I use requestOrNone.get inside case statement to get the action Request object. Is it type safe, since case statement matched? I find it a bit of ugly. Is it a way to "unwrap" the Request object from Some, but still be able to match Request class fields?
What if I want a complex calculation inside a case with local variables, etc... Can I use {} blocks after case statements? I use IntelliJ Idea with official Scala plugin and it highlights my brackets, suggesting to remove them.
If that is possible, is it good practice to enclose matches in matches?
... match {
case Some(Request("GET", path, _)) => {
var stream = this.getStream(path)
stream match {
case Some(InputStream) => Response.stream(stream.get)
case None => new Response(404, "Not Found)
}
}
}
For the first part of your question, you can name the value you match against with # :
scala> case class A(i: Int)
defined class A
scala> Option(A(1)) match {
| case None => A(0)
| case Some(a # A(_)) => a
| }
res0: A = A(1)
From the Scala Specifications (8.1.3 : Pattern Binders) :
A pattern binder x#p consists of a pattern variable x and a pattern p.
The type of the variable x is the static type T of the pattern p. This
pattern matches any value v matched by the pattern p, provided the
run-time type of v is also an instance of T , and it binds the
variable name to that value.
However, you do not need to in your example: since you're not matching against anything about the Request but just its presence, you could do :
case Some(req) => new Response(405, "Method Not Allowed", req)
For the second part, you can nest matches. The reason Intellij suggests removing the braces is that they are unnecessary : the keyword case is enough to know that the previous case is done.
As to whether it is a good practice, that obviously depends on the situation, but I would probably try to refactor the code into smaller blocks.
You can rewrite the pattern as following (with alias).
case Some(req # Request(_, _, _)) => new Response(405, "Method Not Allowed", req)
You cannot use code block in pattern, only guard (if ...).
There are pattern matching compiler plugin like rich pattern matching.
I have a Java enum type that has some Strings and I want to pattern match against in. Here is what I have done so far:
public enum MyEnum {
YEAR, MONTH;
}
In my scala function, I do the following:
timePeriod.toUpperCase match {
case MyEnum.YEAR.name => doSomething
case MyEnum.MONTH.name => doSomething
}
When I compile, I get the following error:
stable identifier required, but YEAR.name found
It is not informative enough for me to understand the root cause of the error. Any ideas?
You can't have method calls as clauses in a match, because the result of the method may differ. We know in this case it doesn't but there's no way to indicate to the compiler that a method call is constant.
You could do this:
timePeriod.toUpperCase match {
case period if period == MyEnum.YEAR.name =>
case period if period == MyEnum.MONTH.name =>
}
Which is a bit more verbose. Someone else may have a shorter and better suggestion.
You could use the valueOf method of a Java Enum to do the lookup:
MyEnum.valueOf(timePeriod.toUpperCase) match {
case MyEnum.YEAR => doSomething
case MyEnum.MONTH => doSomething
}
The resolution at MyEnum.valueOf method is strict and will throw an java.lang.IllegalArgumentException if the value being resolved is not part of the enum.
If you expect values not resolved by the Enum, you may want to contain the exception and add a default match to handle it. An idiomatic way to do that would be:
import scala.util.{Try, Success, Failure}
Try{MyEnum.valueOf(timePeriod.toUpperCase)} match {
case Success(MyEnum.YEAR) => doSomething
case Success(MyEnum.MONTH) => doSomething
case Failure(_) => handleDefault
}
I'm trying to do some patting matching in Scala and I'm running into some problems. Here's my code (minus the fluff):
realtionships.filter(...) match {
case (parent: Relationship) :: Nil => parent.endNode
case _ => throw new Exception
}
The gist is that I want a list that is only a single item that is of type Relationship. If it's anything else, throw an Exception. But the compiler is giving me this error:
constructor cannot be instantiated to expected type
found: scala.collection.immutable.::[B]
required: scala.collection.immutable.Set[Relationship]
Why exactly am I getting this error? Am I not allowed to match the elements of a list while also trying to match the type? Or do I just have the wrong syntax? (Side note: Relationship is a case class.)
The compiler will refuse a pattern match if it can deduce that you are trying to match types which cannot be equal. From the error message is appears that relationships is a Set and you are trying to match for a List. Now a Set can never be a List, so the compiler rightfully rejects that code.
If you want a List actually, you can enforce it:
relationships.filter(...).toList match {
..
}
If you want to stick to a Set, you would need an extractor on Set. That doesn't exist, however... Here is a question related with an answer that shows you to write a custom extractor. If you don't want to go through this effort, a poor man's solution would be
val f = relationships.filter(...)
f.headOption match {
case Some(parent: Relationship) if f.size == 1 => parent.endNode
case _ => throw new Exception
}
(Note however that size is an O(N) operation)