Reputation: 19854
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?
Upvotes: 1
Views: 335
Reputation: 15472
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]]
Upvotes: 1
Reputation: 170713
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.
Upvotes: 3