Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using mapTo with futures in Akka/Scala

I've recently started coding with Akka/Scala, and I've run into the following problem:

With a implicit conversion in scope, such as:

implicit def convertTypeAtoTypeX(a: TypeA): TypeX =
    TypeX() // just some kinda conversion

This works:

returnsAFuture.mapTo[TypeX].map { x => ... }

But this doesn't:

returnsAFuture.mapTo[TypeX].onComplete { ... }

The latter fails with a type cast exception. (i.e. TypeA cannot be cast to TypeX)

Very confused. Why? I suspect it has something to do with Try, but I don't know enough about either to guess at any sort of answer :(

Thanks!

like image 868
qqqqq Avatar asked Mar 28 '15 05:03

qqqqq


1 Answers

From doc:

def mapTo[S](implicit tag: ClassTag[S]): Future[S]  
    Creates a new Future[S] which is completed with this Future's result if that conforms to S's erased type or a ClassCastException otherwise.

This function can only be used to cast between objects that are in some inheritance relationship. It doesn't expect any implicit evidence to convert from [T] to [S] (it doesn't even know about T!)

This function is used e.g. in Akka where you ask an actor and receive in response Future[Any]. But you know that an Actor will return you String so you can safely write actor.ask(...).mapTo[String] and this will work because Any can be casted to everything. No implicit conversions are used here.

Now you are saying your first example works. But this line is not even computed as you never request for a result. To visualize, the Scala compiler says: well you're only doing a map (change from type X to type Y) on a result of this future, but you never actually use it, so why bother even executing it if you don't care yourself?

If you added onComplete after your map in first line you would see the same ClassCastException.

This is probably now what you want but this is interesting:

returnsAFuture.map { x => x.fieldOnlyInTypeX }

if you use "x" as if it was of type TypeX everything will work just fine. Scala compiler will apply implicit conversion to "x" to convert it to TypeX. This is probably not what you want because "x" is still of type TypeA and is converted by implicit on each use in map.

~Krzysiek

like image 186
kpbochenek Avatar answered Nov 04 '22 04:11

kpbochenek