Class cast exceptions in actors that return Future[Unit]

284 views
Skip to first unread message

Alan Burlison

unread,
Jan 31, 2017, 1:36:05 PM1/31/17
to Akka User List
I'm writing an Akka persistence journal that saves data in JSON format.
I've done that as normal, by subclassing AsyncWriteJournal and
implementing the necessary methods.

The actual file IO is done by sub-Actors, one per output file where each
persistent actor has its own JSON file. The read/write methods on the IO
Actor which return a value via 'ask' return a Future[Any] as per normal.
However the asyncXXX methods in AsyncWriteJournal return Future[Unit],
so the Future[Any] returned from the IO Actor needs to be converted to a
Future[Unit].

I've tried a couple of ways of doing that:

1) Casting the return value with ".asInstanceOf[Future[Unit]]". This
generates a ClassCast exception:

2) Applying ".mapTo[Unit]" to the return value. This generates a
ClassCast exception:

3) Applying ".map(_ => ())" to the return value. This works, but sort of
smells a bit.

Is there a cleaner way of doing this?

--
Alan Burlison
--

Akka Team

unread,
Jan 31, 2017, 3:32:56 PM1/31/17
to Akka User List
You have a Future[Something], and a Something is an Any (everything is) but it is not Unit (only Unit is), so you can not just cast it, you must replace it with an actual Unit, which is what .map(_ => ()) does.

-- 
Johan
Akka Team



--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+unsubscribe@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.




Alan Burlison

unread,
Jan 31, 2017, 4:28:59 PM1/31/17
to akka...@googlegroups.com
On 31/01/2017 20:32, Akka Team wrote:

> You have a Future[Something], and a Something is an Any (everything is) but
> it is not Unit (only Unit is), so you can not just cast it, you must
> replace it with an actual Unit, which is what .map(_ => ()) does.

OK, thanks for confirming that I haven't missed anything obvious.

However that's a bit clunky - the method in the actor returns a
Future[Unit], by the time it gets back to the "ask"ing Actor is has been
converted to a Future[Any] and then you have to map it back to a
Future[Unit] again.

--
Alan Burlison
--

Viktor Klang

unread,
Jan 31, 2017, 4:36:56 PM1/31/17
to Akka User List
What'd be the alternative?

--
Cheers,

Alan Burlison

unread,
Jan 31, 2017, 4:41:33 PM1/31/17
to akka...@googlegroups.com
On 31/01/2017 21:36, Viktor Klang wrote:

> What'd be the alternative?

Not sure really, don't know if there's any way of preserving a
Future[Unit] rather than converting it to a Future[Any]. As I said, it
just seemed a bit clunky, and not obvious immediately obvious as to how
to solve the issue. Perhaps just a note in the docs about how to handle
Future[Unit]?

--
Alan Burlison
--

Akka Team

unread,
Jan 31, 2017, 4:55:18 PM1/31/17
to Akka User List
If it in fact was a Unit you got back from the actor then neither of the things you tried should throw a class cast exception though. If the actor for example sends a Future[Unit] back, then you will have a Future[Future[Unit]] returned from ask.

-- 
Johan
Akka Team



--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+unsubscribe@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Akka Team
Lightbend - Reactive apps on the JVM
Twitter: @akkateam

Viktor Klang

unread,
Jan 31, 2017, 5:18:54 PM1/31/17
to Akka User List
The answer will be in the stack traces.

--
Cheers,

Alan Burlison

unread,
Jan 31, 2017, 6:20:21 PM1/31/17
to akka...@googlegroups.com
On 31/01/17 22:18, Viktor Klang wrote:

> The answer will be in the stack traces.

What I got was:

java.lang.ClassCastException: Cannot cast scala.util.Success to
scala.runtime.BoxedUnit

which didn't give me much of a clue, however it was clear that
asInstanceOf wasn't the right approach and when I looked at the mapTo
implementation it was going to throw an exception as well, which is why
I settled on the map alternative - but that didn't feel quite right
either, hence the question. Thanks for the confirmation that's the right
approach.

--
Alan Burlison
--

Viktor Klang

unread,
Jan 31, 2017, 6:34:56 PM1/31/17
to Akka User List
I think the problem is that your responding with a scala.util.Success rather than a akka.actor.Status.Success.



--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+unsubscribe@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

Alan Burlison

unread,
Jan 31, 2017, 7:03:34 PM1/31/17
to akka...@googlegroups.com
On 31/01/17 23:34, Viktor Klang wrote:

> I think the problem is that your responding with a scala.util.Success
> rather than a akka.actor.Status.Success.

Ahah! I think you may of nailed it... Thanks!

--
Alan Burlison
--

Alan Burlison

unread,
Jan 31, 2017, 8:55:34 PM1/31/17
to akka...@googlegroups.com
> Ahah! I think you may of nailed it... Thanks!

Indeed you did nail it - "thanks" doesn't come close as I'd looked at
this for so long that I'd gone completely snow-blind ;-)

Is there a convenient shorthand way of mapping between a
scala.util.Success and an akka.actor.Status.Success, or should I just do
it with a match expression? What I'm doing is wrapping the IO functions
that could fail in a "Try { ??? }" and returning the result to the
calling actor.

Is there a reason why there's both scala.util.Success and an
akka.actor.Status.Success?

--
Alan Burlison
--

Viktor Klang

unread,
Feb 1, 2017, 4:06:52 AM2/1/17
to Akka User List
On Wed, Feb 1, 2017 at 2:55 AM, Alan Burlison <alan.b...@gmail.com> wrote:
Ahah! I think you may of nailed it... Thanks!

Indeed you did nail it - "thanks" doesn't come close as I'd looked at this for so long that I'd gone completely snow-blind ;-)

You're welcome. A reminder that the actual error messages are very important to include. :)
 

Is there a convenient shorthand way of mapping between a scala.util.Success and an akka.actor.Status.Success, or should I just do it with a match expression? What I'm doing is wrapping the IO functions that could fail in a "Try { ??? }" and returning the result to the calling actor.

If there is no method in the java/scaladoc then you'll need to convert manually. And if you need a shorthand, it should be a one-liner def. ;)
 

Is there a reason why there's both scala.util.Success and an akka.actor.Status.Success?

IIRC akka.actor.Status.Success was created aeons ago, scala.util.Success was added with scala.util.Try,
so they have separate origins. (just like java.util.List and scala.collection.immutable.List)
 


--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+unsubscribe@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

Alan Burlison

unread,
Feb 1, 2017, 4:51:38 AM2/1/17
to akka...@googlegroups.com
On 01/02/17 09:06, Viktor Klang wrote:

> You're welcome. A reminder that the actual error messages are very
> important to include. :)

Yes, I consider my wrist to be slapped ;-) Thanks again!

> If there is no method in the java/scaladoc then you'll need to convert
> manually.

If there is I haven't been able to spot it.

> And if you need a shorthand, it should be a one-liner def. ;)

Well, nearly ;-) I just copied the "Try {???}" implementation but made
it return Akka Status values rather those used by Try - I don't need any
operations other than to return the Akka success types.

def actorTry[T](f: => T): akka.actor.Status.Status = {
try {
akka.actor.Status.Success(f)
} catch {
case NonFatal(e) => akka.actor.Status.Failure(e)
}
}

then in the receive method:

case Read(from, to, reader) => sender ! actorTry { read(from, to, reader) }

> IIRC akka.actor.Status.Success was created aeons ago,
> scala.util.Success was added with scala.util.Try, so they have
> separate origins. (just like java.util.List and
> scala.collection.immutable.List)

Ah, the curse of history :-) Sounds completely plausible - thanks.

--
Alan Burlison
--

Viktor Klang

unread,
Feb 1, 2017, 5:19:34 AM2/1/17
to Akka User List
On Wed, Feb 1, 2017 at 10:51 AM, Alan Burlison <alan.b...@gmail.com> wrote:
On 01/02/17 09:06, Viktor Klang wrote:

You're welcome. A reminder that the actual error messages are very
important to include. :)

Yes, I consider my wrist to be slapped ;-) Thanks again!

lol, no wrist-slapping intended—but the more info is available, the more people has a chance to understad.
 


If there is no method in the java/scaladoc then you'll need to convert
manually.

If there is I haven't been able to spot it.

Try(block).fold(Status.Success(_), Status.Failure(_)) ?
 


And if you need a shorthand, it should be a one-liner def. ;)

Well, nearly ;-) I just copied the "Try {???}" implementation but made it return Akka Status values rather those used by Try - I don't need any operations other than to return the Akka success types.

  def actorTry[T](f: => T): akka.actor.Status.Status = {
    try {
      akka.actor.Status.Success(f)
    } catch {
      case NonFatal(e) => akka.actor.Status.Failure(e)
    }
  }

then in the receive method:

case Read(from, to, reader) => sender ! actorTry { read(from, to, reader) }

IIRC akka.actor.Status.Success was created aeons ago,
scala.util.Success was added with scala.util.Try, so they have
separate origins. (just like java.util.List and
scala.collection.immutable.List)

Ah, the curse of history :-) Sounds completely plausible - thanks.

:)
 


--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+unsubscribe@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

Alan Burlison

unread,
Feb 1, 2017, 5:41:20 AM2/1/17
to akka...@googlegroups.com
On 01/02/2017 10:19, Viktor Klang wrote:

> Try(block).fold(Status.Success(_), Status.Failure(_))

Neat, I wasn't aware of that - it appeared in 2.12:

https://issues.scala-lang.org/browse/SI-8336

Ta :-)

--
Alan Burlison
--
Reply all
Reply to author
Forward
0 new messages