trait Future[T]{
def onComplete( callback: Try[T] => Unit )(...):Unit
}
trait Socket{
def sendToEurope( packet:Array[Byte] ):Future[Array[Byte]]
}
val c:Future[Array[Byte]] = packet onComplete {
case Success(p) => socket.sendToEurope(p)
....
}
this a sample quoted from the class note of coursera "Reactive programming"
I was trying to understanding the method signature here. onComplete takes a Try => Unit function type, while the bracket section is a Success=>FutureType. I don't see how the 2 types are compatible here. Taking variance into consideration: Function1[-A,+R] which makes Success compatible, but I still don't see Future covariant with Unit here.
can someone explain this to me ?
Your understanding of the code is correct, that it does not compile.
Future.onComplete returns a Unit and therefore cannot return a Future[Array[Byte]] despite it being return type of socket.sendToEurope.
The code is correct. Any value will be automatically converted to Unit if Unit is the expected type. The rule is there for these types of situations, where otherwise you would have to do:
val c:Future[Array[Byte]] = packet onComplete {
case Success(p) => socket.sendToEurope(p); ()
....
}
Which would be ugly.
See Scala: Why can I convert Int to Unit?
Related
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 working on an existing code base with a wrapper class around Slick 2.1.0 (I know). This wrapper has a method named transaction that is a generic - it takes a (f: => T) (so it's pass-by-name). I need to mock this class for an unit test. We're also using Mockito 1.10.19 (again, I know), which won't let me mock a pass-by-name (I believe...). So I'm stuck implementing the underlying trait that this wrapper class is built on.
The immediate problem is this: I want to mock this transaction method so it does nothing. The code I'm testing passes in a (f: => Unit). So I want to implement this method to return a Future.Done. (Did I mention we're using Finagle and not Scala futures?) But this method is generic. How do I properly specialize?
This is my current attempt:
val mockDBM = new DatabaseManager {
override def transaction[#specialized(Unit) T](f: => T): Future[T] = Future.value(f)
def transaction(f: => Unit): Future[Unit] = Future.Done
}
Of course, I get a have same type after erasure error upon compilation. Obviously I have no idea how #specialized works.
What do I do? Maybe I can use Mockito after all? Or I need to learn what specializing a generic method actually means?
I found this, which probably contains the answer, but I have no formal background in FP, and I don't grok this at all: How can one provide manually specialized implementations with Scala specialization?
#specialized doesn't let you provide specializations, it just generates its own. The answer provided in the linked question would require changing the signature. From the question it looks like you can't change it, in which case you are out of luck. If you can... you may still be out of luck, depending on how exactly this code is going to be called.
OTOH, the solution for "I want to disregard f, but can only return Future.Done if the generic is for a Unit type" is far simpler:
class Default[A] {
var x: A = _
}
object Default {
def apply[A]() = (new Default[A]).x
}
val mockDBM = new DatabaseManager {
override def transaction[T](f: => T): Future[T] = {
Future.value(Default(x))
}
}
Assuming you need a successful future, but don't care about value, that is; if you just need any future, override def transaction[T](f: => T): Future[T] = Future.???.
My actual use-case is unit testing code involving finagle FuturePool: I want to make sure, FuturePool.apply was actually invoked, so that the task was executed in the correct instance of the pool.
The problem I am running into however seems more generic, so I will illustrate it on an abstract example, not related to finagle or futures.
Suppose, I have these two classes:
class Foo {
def apply(f: => String) = f
}
class Bar(val foo: Foo) {
def doit(f: => String) = foo(f)
}
Bar has an instance of Foo, that knows how to run functions, and I want to test that it is actually using it for execution:
describe("Bar") {
it("should use the right foo") {
val foo = mock[Foo]
when(foo.apply(any)).thenAnswer( new Answer[String] {
def answer(invocation: InvocationOnMock): String =
invocation.getArgumentAt(0, classOf[Function0[String]]).apply()
})
new Bar(foo).doit("foo") should equal("foo")
}
}
This does not work: .doit return null, apparently, because mockito does not realize it was mocked. It seems that any is not matching Function0 in this case (replacing it with any[Function0[String]] does not help either.
I also tried it another way:
it("should Foo!") {
val foo = Mockito.spy(new Foo)
new Bar(foo).doit("foo") should equal("foo")
verify(foo).apply(any)
}
This also does not work, and kinda confirms my suspicion about any not working in this case:
Argument(s) are different! Wanted:
foo$1.apply(
($anonfun$apply$mcV$sp$7) <function0>
);
Actual invocation has different arguments:
foo$1.apply(
($anonfun$apply$mcV$sp$6) <function0>
);
Any ideas about a good way to get around this?
This signature:
def apply(f: => String)
is known as "call by name" where it passes an expression instead of an evaluated expression. This is very specific to Scala and not well supported with Mockito.
There is a host of workarounds to this:
Is there a way to match on a call-by-name argument of a Mockito mock object in Specs?
How to mock a method with functional arguments in Scala?
How do you mock scala call-by name in Mockito
The one by Eric looks the simplest and what you may want.
OK, so I am looking at testing libraries, in particular ScalaTest & ScalaMock.
I wanted to write a test to test this function that I have written:
def gameMenuSelect(): State = {
Try(UI.readOption) match {
case Success(i) => {
i match {
case 1 => HumanGame
case 2 => MachineGame
case 3 => sys.exit(0)
case _ =>
UI.invalidSelectionMsg
ChoosingGame
}
}
case Failure(e) => UI.invalidSelectionMsg; ChoosingGame
}
}
A bit of background, UI.readOption is a simple scala.io.StdIn.readInt.
State is a Trait - subsequently HumanGame, MachineGame and ChoosingGame are also Traits that extend State.
The problem is I have no idea how I would test it, the reason is because I feel like this function does too much.
It is reading input, validating that the input given is indeed a number/integer and not throwing a NumberFormatException. Given that the input is an integer it is match on allowable integers.
I really feel like there is a lot to test, also a lot that I am not sure is unit testable.
Could I have some opinions on whether you feel that this function is doing too many things, whether I should try to break up the reading of the integer and the matching of it?
Thanks.
Yes, should absolutely try to separate the "side-effecting" bits, reading and writing, from the selection logic. The selection logic can return something like
import scalaz._, Scalaz._
def selectGame(i: Int): GameError \/ State =
i match {
case 1 => HumanGame.right
case 2 => MachineGame.right
case _ => InvalidGame(i).left
}
sealed trait GameError
case class InvalidGame(i: Int) extends GameError
object GameError {
def render(e: GameError): String =
e match {
case InvalidGame(i) =>
s"Invalid game choice: $i. Only 1 and 2 are acceptable values"
}
}
Note that I also model the error into a specific type instead of just using strings.
Then you can do the same with your number parsing:
def parseInt(i: String): ParseError \/ Int =
???
For your "effects" you can use Scalaz IO for the interactions with the console:
def readLine: IO[String] =
IO(StdIn.readLine)
def printLine(line: String): IO[Unit] =
IO(println(line))
Then, with a bit more code, you can use the EitherT[IO, E, A] monad to "assemble" all your functions:
// I will provide a full example if you want to go this way
val actions: EitherT[IO, ApplicationError, Unit] =
for {
line <- readLine
i <- parseInt(line)
s <- selectGame(i)
_ <- printLine(s.render)
} yield ()
The actions value will both have IO side-effects and collect errors, stopping the process if there are any.
Eventually this all makes your testing a lot easier because you have isolated the "pure" parts which are way easier to test: no setup, no mocks, just pure functions.
In my opinion, there are too many side effects in your function. Not only the reading of the integer, but also sys.exit(0). You could change the method to accept the integer as a parameter, and also add an EndingGame state that you could use for case 3. You would then have a pure function that is easily testable.
My code heavily uses Akka and untyped actors.
An example of typical logic is as follows:
val myFuture: Future[Any] = akka.pattern.AskSupport.ask(myActorRef, myMessage)
val completedLogic: Future[Unit] = myFuture.map(myFunction)
myFunction then contains a strongly typed signature as follows:
def myFunction(): (Option[MyStronglyTypedClass]) => Unit = {
(myOption: Option[MyStronglyTypedClass]) => myOption foreach (myObject => // do some logic
}
I know that myFuture will always contain an instance of MyStronglyTypedClass or null for this particular actor. I will also know this for other actor/future/function combinations.
My problem comes when I look to create an implicit conversion from the Future[Any] to the Option[MyStronglyTypedClass] or Option[MyOtherStronglyTypedClass]
The implicit conversion will just do a null check and one other piece of logic before creating the Option
How do I go about performing this implicit conversion from Any to a subtype, or is it even possible?
You should, instead, convert to Future[Option[MyStronglyTypedClass]]:
def asMyStronglyTypedClass(x: Any): Option[MyStronglyTypedClass] = x match {
case null => None
case ...
}
// this will fail if myFuture fails or asMyStronglyTypedClass throws
val typedFuture = myFuture.map(asMyStronglyTypedClass)
and do what you want with this future. E.g.
typedFuture.onSuccess(myFunction)
EDIT: I missed you already have a map. In this case the issue is that you don't need to convert Future[Any] to Option, but its result (i.e. Any). You can write e.g. myFuture.map(asMyStronglyTypedClass).map(myFunction) or myFuture.map(x => myFunction(asMyStronglyTypedClass(x))). You could also make asMyStronglyTypedClass implicit and write myFuture.map(x => myFunction(x)). I still think it isn't a good idea, as it could get applied somewhere you don't expect.
If you really want to write myFuture.map(myFunction), you'll need a different implicit conversion to make the compiler understand:
implicit def contraMap(f: Option[MyStronglyTypedClass] => Unit): Any => Unit =
x => f(asMyStronglyTypedClass(x))
Of course, these can be made generic over your types, as mentioned in the comments.
Impliciy converting from Any to something else is something that you should never do because it effectively switches off Scala's type system. Converting the type of a future in a safe fashion can be done using
myFuture.mapTo[Option[MyStronglyTypedClass]]