I have a value like this:
val ss: Option[Future[List[Either[Error, File]]]]
And what I want to do is to lift this to an EitherT.liftF[Future, Error, List[Either[Error, File]]] so what I did was this:
ss match {
case Some(value) => EitherT.liftF[Future, Error, List[Either[Error, File]]](value)
case None => EitherT.leftT[Future, List[Either[Error, File]]](Error("failed"))
}
My question is whether it is correct that I can use EitherT.liftF to lift a value which is already a future because I think normally that is used for values which need to be lifted to a future, not one which is a future itself.
Future has a Monad instance for practical reasons but isn't really lawful. See this post on the topic.
However it will still behave as expected in many cases such as yours.
You can also implement it this way:
EitherT(ss.toRight(Error("failed")).sequence)
Related
I do some data conversion on a list of string and I get a list of Either where Left represents an error and Right represents a successfully converted item.
val results: Seq[Either[String, T]] = ...
I partition my results with:
val (errors, items) = results.partition(_.isLeft)
After doing some error processing I want to return a Seq[T] of valid items. That means, returning the value of all Right elements. Because of the partitioning I already knew that all elements of items Right. I have come up with five possibilities of how to do it. But what is the best in readability and performance? Is there an idiomatic way of how to do it in Scala?
// which variant is most scala like and still understandable?
items.map(_.right.get)
items.map(_.right.getOrElse(null))
items.map(_.asInstanceOf[Right[String, T]].value)
items.flatMap(_.toOption)
items.collect{case Right(item) => item}
Using .get is considered "code smell": it will work in this case, but makes the reader of the code pause and spend a few extra "cycles" in order to "prove" that it is ok. It is better to avoid using things like .get on Either and Option or .apply on a Map or a IndexedSeq.
.getOrElse is ok ... but null is not something you often see in scala code. Again, makes the reader stop and think "why is this here? what will happen if it ends up returning null?" etc. Better to avoid as well.
.asInstanceOf is ... just bad. It breaks type safety, and is just ... not scala.
That leaves .flatMap(_.toOption) or .collect. Both are fine. I would personally prefer the latter as it is a bit more explicit (and does not make the reader stop to remember which way Either is biased).
You could also use foldRight to do both partition and extract in one "go":
val (errors, items) = results.foldRight[(List[String], List[T])](Nil,Nil) {
case (Left(error), (e, i)) => (error :: e, i)
case ((Right(result), (e, i)) => (e, result :: i)
}
Starting in Scala 2.13, you'll probably prefer partitionMap to partition.
It partitions elements based on a function which returns either Right or Left. Which in your case, is simply the identity:
val (lefts, rights) = List(Right(1), Left("2"), Left("3")).partitionMap(identity)
// val lefts: List[String] = List(2, 3)
// val rights: List[Int] = List(1)
which let you use lefts and rights independently and with the right types.
Going through them one by one:
items.map(_.right.get)
You already know that these are all Rights. This will be absolutely fine.
items.map(_.right.getOrElse(null))
The .getOrElse is unnecessary here as you already know it should never happen. I would recommend throwing an exception if you find a Left (somehow) though, something like this: items.map(x => x.right.getOrElse(throw new Exception(s"Unexpected Left: [$x]")) (or whatever exception you think is suitable), rather than meddling with null values.
items.map(_.asInstanceOf[Right[String, T]].value)
This is unnecessarily complicated. I also can't get this to compile, but I may be doing something wrong. Either way there's no need to use asInstanceOf here.
items.flatMap(_.toOption)
I also can't get this to compile. items.flatMap(_.right.toOption) compiles for me, but at that point it'll always be a Some and you'll still have to .get it.
items.collect{case Right(item) => item}
This is another case of "it works but why be so complicated?". It also isn't exhaustive in the case of a Left item being there, but this should never happen so there's no need to use .collect.
Another way you could get the right values out is with pattern matching:
items.map {
case Right(value) => value
case other => throw new Exception(s"Unexpected Left: $other")
}
But again, this is probably unnecessary as you already know that all values will be Right.
If you are going to partition results like this, I recommend the first option, items.map(_.right.get). Any other options either have unreachable code (code you'd never be able to hit through Unit tests or real-life operation) or are unnecessarily complicated for the sake of "looking functional".
I have a future for which I care if it completes successfully, but the result is meaningless. One such example is a Future that saves or deletes a record from a DB.
What is the best way to represent such future? Future[Any]? Future[Unit]?
Future[Unit] is the normal way. It shows a bit more intent than Future[Any]. ie. You know that there is nothing within the future that you care about.
Future[Unit] would be better. You can use callback with your future as it returns unit. So, there will be success or failure.
futureResult.onComplete{
case Success(result) => //code
case Failure(ex) => ex.printStackTrace
}
Introduction
I had created a lovely one-liner:
Option("something").map(_ => Try("something else")).flatten.getOrElse("default")
which actually does not compile, with error:
Error:(15, 31) Cannot prove that scala.util.Try[String] <:< Option[B].
Option("").map(_ => Try("")).flatten.getOrElse("");}
^
so I had found a way around:
Option("something").flatMap(_ => Try("something else").toOption).getOrElse("default")
But, the problem
My colleague warned me, that my construction is actually loosing the error information. This is true, and in real-life application - not acceptable.
After getting rid of all the repetition I had ended up with:
implicit class CoolTry[T](t: Try[T]) extends StrictLogging {
def toOptionSE: Option[T] = t match {
case Success(s) => Some(s)
case Failure(ex) =>
logger.error(ex.getMessage, ex)
None
}
}
using:
Option("something").flatMap(_ => Try(new Exception("error")).toOptionSE).getOrElse("default")
Question
I believe there are many similar cases in every application and I simply do not know if either my approach is bad or Try().toOption is simply done wrong?
I understand that logging is a side effect, but while using Try I guess everyone does expect it if something goes wrong?
Can the implicit class be improved?
Is there any utility library handling Try().toOption my way?
Or what (other) approach should I take here?
Thanks!
Forcing logging every time you change a Try[T] to an Option[T] is an undesired effect IMO. When you do such a transformation you're explicitly admitting that you don't really care about the internals of the failure, if it happened. All you want is to access the result, if it exists. Most of the time you say "well, this is undesirable, I always want to log exceptions", but sometimes you simply only care about the end result, so dealing with an Option[T] can be good enough.
Or what (other) approach should I take here?
Using Either[A, B] is an option here, especially in Scala 2.12 when it became right biased. You can simply map over it and only at the end check if there was an error and then log (created with Scala 2.12.1):
val res: Either[Throwable, String] = Option("something")
.map(_ => Try("something else").toEither)
.getOrElse(Right("default"))
.map(str => s"I got my awesome $str")
Ideally (IMO) deferring the logging side effect to the last possible point would serve you better.
One possible improvement would be to make it crystal clear to the user of what is going on; between the implicit being injected somewhere by the compiler and the apparently "pure" name (toOptionSE) it may not be evident of what is going on for a second developer reading and/or modifying your code. Furthermore, you're fixing how you treat the error case and don't leave the opportunity to handle it differently from logging it.
You can treat errors by leveraging projection, like the failed projection defined over Try. If you really want to do this fluently and on one line, you can leverage implicit classes like this.
implicit class TryErrorHandlingForwarding[A](t: Try[A]) {
def onError(handler: Throwable => Unit): Try[A] = {
t.failed.foreach(handler)
t
}
}
// maybe here you want to have an actual logger
def printStackTrace: Throwable => Unit =
_.printStackTrace
Option("something").
flatMap(_ => Try(???).onError(printStackTrace).toOption).
getOrElse("default")
Also, here I'm assuming that for whatever reason you cannot use Try right from the start (as it's been suggested in a comment).
So usually when we run a method that can both fail and return a value, we can encode our method return type as Either[SomeErrorType, ReturnType]. But many times we're running a method for its side effects, so the return type is Unit.
I could of course return an Either[SomeErrorType, Unit] but that definitely looks odd.
I could also just return an Option[SomeErrorType] but it doesn't really look a lot better (and breaks a possibly existing symmetry with other Either[SomeErrorType, NonUnitReturnType]s.
What's your approach in these cases?
def m(): Unit // and implicitly know that exceptions can be thrown?;
def m(): Either[SomeErrorType, Unit] // this is odd;
def m(): Option[SomeErrorType] // this is odd, as it makes it look as the return type ofm()on a successful run is an error code.
Other that I can't think of?
Thanks
I use Try[Unit] for that case.
It encodes that the result of the method either succeeds or fails with some Exception, which can be further processed.
vs T => Unit Try lifts errors to the application level, encoding in the signature that some error can be expected and allowing the application to handle it as a value.
vs. Option[T] => Option is only able to encode that the operation had a value or not
vs. Either[SomeErrorType, Unit] => Try It's easier to work with using monadic constructions.
I've used something like this to implement checks. (imaginary example)
for {
entity <- receiveEntity // Try[Entity]
_ <- isRelational(entity)
_ <- isComplete(entity)
_ <- isStable(entity)
} yield entity
where each check is of the form: Entity => Try[Unit]
This will return the entity if all checks pass of the first error that failed the check.
One more option that hasn't been mentioned yet is Validated from cats. All the options mentioned so far (Try, Either, Option) are monads, while Validated is an applicative functor. In practice this means you can accumulate errors from multiple methods returning Validated, and you can do several validations in parallel. This might not be relevant to you, and this is a bit orthogonal to the original question, but I still feel it's worth mentioning in this context.
As for the original question, using Unit return type for a side-effecting function is perfectly fine. The fact this function can also return error shouldn't get in your way when you define the "real" (right, successful, etc.) return type. Therefore, if I were to select from your original options, I'd go for Either[Error, Unit]. It definitely doesn't look odd to me, and if anyone sees any drawbacks in it, I'd like to know them.
I'm fairly new to Scala so please be gentle.
In the app I'm currently building, I'm using Akka actors and I want to write some unit tests. I came across this official documentation for writing unit tests for Akka actors
but I couldn't understand exactly how it should work. In particular,
val actorRef = TestActorRef(new MyActor)
// hypothetical message stimulating a '42' answer
val future = actorRef ? Say42
val Success(result: Int) = future.value.get
result must be(42)
When I try that, I get not found: value Success, which is not surprising.
I then found this example of how to test Scala actors
val actorRef = TestActorRef[TickTock]
implicit val timeout = Timeout(5 seconds)
val future = (actorRef ? new Tick("msg")).mapTo[String]
val result = Await.result(future, timeout.duration)
Assert.assertEquals("processed the tick message", result)
, which admittedly is possibly old, but it is easy to understand and closer to what I normally use when I want to use Futures, and most importantly works. It does require me to declare a few implicits like the ActorSystem, timeout and such, which doesn't seem to be the case with the official way...
If possible, I'd like to use the method proposed by the official documentation, so I would appreciate it if someone could help me understand how it works (in particular the Success bit) and how to use it.
The answer to your question might be too long, because it is impossible to know how much Scala you actually know. I will try to make my answer as short as possible, but do not hesitate to ask for clarification at any point. I also apologize on behalf of the whole stackoverflow community for making you feel the need to apologize due to an apparent lack of skill before asking a question.
In Scala 2.10 a concept of Try was introduced. It is very similar to Option. Option is a concept of handling nulls. A value of type Option can take two forms: Some(value) or None. When you have an Optional value you can pattern match on it to see if it is a Some or a None and then act accordingly. Pattern matching occurs in many places in Scala and one of them is during the initialization of vals. Here are few examples:
val x = 10 // pattern 'x' on the LHS matches any value on the RHS so 'x' is initialized with 10
val Some(x) = Some(10) // pattern 'Some(x)' on the LHS matches any value of type 'Some' and binds it's value to x, so 'x' is yet again initialized with 10
Try is a concept of handling exceptions. A value of type Try can take two forms: Success(result) or Failure(throwable). When you have a value of type Try you can pattern match on it to see if it is a Success or a Failure.
This is what happens in your code (pattern matching on Success). In contrast to Option the two forms of Try are not in scope by default, which causes the compilation error. This will fix it:
import scala.util.{Try, Success, Failure}
Have your test extend the TestKit and then add "with ImplicitSender" and then you can do things like:
val yourActor = system.actorOf(Props[MyActor])
yourActor ! Say42
expectMsg(42)
Firstly it's not a good pattern to use get on futures value, this can raise an exception if there was a failure. You should use either Await.result, like in your seconds example, or use pattern matching to work with Success and Failure:
future match {
case Success(value) => // work with value
case Failure(ex) => // work with exception
}
to use Success and Failure import scala.util._ or scala.util.{Success, Failure}
Here is an official documentation for the latest release 2.2-M3.