Future.flatMap

615 views
Skip to first unread message

Michael Slinn

unread,
Mar 6, 2012, 12:56:23 PM3/6/12
to akka...@googlegroups.com
While reading the Future.flatMap docs I noticed that the Scala and Java examples were not mirrors of each other; there is a potentially significant difference for the reader. The Scala version demonstrates a typical for-comprehension; it computes the value of Future f3 by multiplying the length of a string computed in future f1 with the completed value of the Future f2 (which is 3):

  1. val f1 = Future {
  2. "Hello" + "World" // there is no Thread.sleep() here either, but this is less important
  3. }
  4. val f2 = Promise.successful(3)
  5. val f3 = f1 flatMap { x
  6. f2 map { y
  7. x.length * y
  8. }
  9. }
  10. val result = Await.result(f3, 1 second)
  11. result must be(30)

The Java version does not do the multiplication by the value of another Future in apply() and hence does not show how the same for-comprehension could be implemented in Java:

  1. Future<String> f1 = future(new Callable<String>() {
  2. public String call() throws Exception {
  3. Thread.sleep(100);
  4. return "Hello" + "World";
  5. }
  6. }, system.dispatcher());
  7.  
  8. Future<Integer> f2 = f1.map(new Mapper<String, Integer>() {
  9. public Integer apply(String s) {
  10. return s.length();
  11. }
  12. });

This is significant because trying to write Java code that uses Mapper to implement a for-comprehension is somewhat mind-bending; it would be most helpful if the Java example showed how to write equivalent code that mirrors the entire for-comprehension described in the Scala example. I know that the Java example would grow in length, but that's simply the nature of Java. It might be best for the reader to see the entire converted for-comprehension as a separate code example (by that I mean another iteration of the existing code example), otherwise it might be overwhelming.

Mike

√iktor Ҡlang

unread,
Mar 6, 2012, 1:00:27 PM3/6/12
to akka...@googlegroups.com
Well, you can't implement a for comprehension in Java, since it's a compile-time source expansion in Scala.

So, barring that, what do you feel is missing (code)?

Cheers,



--
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To view this discussion on the web visit https://groups.google.com/d/msg/akka-user/-/OE1TD-rVd9kJ.
To post to this group, send email to akka...@googlegroups.com.
To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.



--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Mike Slinn

unread,
Mar 6, 2012, 1:03:27 PM3/6/12
to akka...@googlegroups.com
The Scala code does flatMap => map
The Java code just does map.

The missing code is the enclosing flatMap around the map.

Mike

Michael Slinn

unread,
Mar 6, 2012, 1:06:28 PM3/6/12
to akka...@googlegroups.com
There is also this other Java code example on the same page, which shows flatMap, but again it does not match the Scala example because it does not contain a map:

    1. Future<String> f1 = future(new Callable<String>() {
    1. public String call() {
    1. return "Hello" + "World";
    2. }
    3. }, system.dispatcher());
    4.  
    1. Future<Integer> f2 = f1.flatMap(new Mapper<String, Future<Integer>>() {
    2. public Future<Integer> apply(final String s) {
    3. return future(new Callable<Integer>() {
    4. public Integer call() {
    5. return s.length();
    6. }
    7. }, system.dispatcher());
    8. }
    9. });

    Mike

    Michael Slinn

    unread,
    Mar 6, 2012, 4:58:24 PM3/6/12
    to akka...@googlegroups.com
    I have put together a Java code example that shows a Scala for-comprehension equivalent expressed as flatMaps followed by a map in Java. It works fine, however it only works because it uses constant values. I then tried changing the computation for Future f2 to accept a Tuple2 instead of ignoring the apply parameter, so I could pass in the two values to be computed:

    Future<Integer> f2a = f1a.flatMap(new Mapper<Tuple2<Integer, Integer>, Future<Integer>>() {
      public Future<Integer> apply(final Tuple2<Integer, Integer> tuple2) {
        return Futures.future(new ExpCalc(tuple2._1(), tuple2._2()), dispatcher);
      }
    });

    The compiler error was "<A>flatMap(scala.Function1<java.lang.Integer,akka.dispatch.Future<A>>) in akka.dispatch.Future<java.lang.Integer> cannot be applied to (<anonymous akka.dispatch.Mapper<scala.Tuple2<java.lang.Integer,java.lang.Integer>,akka.dispatch.Future<java.lang.Integer>>>)"

    Presumably this is because the implementation of flatMap for Java requires that it receive a type that matches the type of the future it is bound to? ... or am I missing something?

    Mike

    √iktor Ҡlang

    unread,
    Mar 6, 2012, 5:08:44 PM3/6/12
    to akka...@googlegroups.com
    Have you've tried supplying the type parameter to flatMap and/or Futures.future?

    Cheers,
     

    Mike

    --
    You received this message because you are subscribed to the Google Groups "Akka User List" group.
    To view this discussion on the web visit https://groups.google.com/d/msg/akka-user/-/Q8KgJ6WGGicJ.

    To post to this group, send email to akka...@googlegroups.com.
    To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
    For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

    Mike Slinn

    unread,
    Mar 6, 2012, 5:09:49 PM3/6/12
    to akka...@googlegroups.com
    I don't understand what you mean.

    Mike

    √iktor Ҡlang

    unread,
    Mar 6, 2012, 5:17:33 PM3/6/12
    to akka...@googlegroups.com

    defflatMap [A] (f: (T) ⇒ Future[A])Future[A]

    Creates a new Future by applying a function to the successful result of this Future, and returns the result of the function as the new Future. If this Future is completed with an exception then the new Future will also contain this exception. Example:

    val future1 = for {
      a: Int    <- actor ? "Hello" // returns 5
      b: String <- actor ? a       // returns "10"
      c: String <- actor ? 7       // returns "14"
    } yield b + "-" + c
    

    Attributes
    final


    Java does not have type inference.

    On Tue, Mar 6, 2012 at 11:09 PM, Mike Slinn <msl...@gmail.com> wrote:
    I don't understand what you mean.


    Mike

    --
    You received this message because you are subscribed to the Google Groups "Akka User List" group.
    To post to this group, send email to akka...@googlegroups.com.
    To unsubscribe from this group, send email to akka-user+unsubscribe@googlegroups.com.

    For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

    Mike Slinn

    unread,
    Mar 6, 2012, 5:19:57 PM3/6/12
    to akka...@googlegroups.com
    So what does this mean for the Java issue I raised?

    Mike

    √iktor Ҡlang

    unread,
    Mar 6, 2012, 5:25:07 PM3/6/12
    to akka...@googlegroups.com
    On Tue, Mar 6, 2012 at 11:19 PM, Mike Slinn <msl...@gmail.com> wrote:
    So what does this mean for the Java issue I raised?

    "Have you've tried supplying the type parameter to flatMap and/or Futures.future?"

    So, did you try to be specific in your Java code, about the type of A in flatMap, or not?




    Mike

    --
    You received this message because you are subscribed to the Google Groups "Akka User List" group.
    To post to this group, send email to akka...@googlegroups.com.
    To unsubscribe from this group, send email to akka-user+unsubscribe@googlegroups.com.
    For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

    Mike Slinn

    unread,
    Mar 6, 2012, 5:29:07 PM3/6/12
    to akka...@googlegroups.com
    You see the code. What needs to change?

    Mike

    √iktor Ҡlang

    unread,
    Mar 6, 2012, 5:33:48 PM3/6/12
    to akka...@googlegroups.com
    On Tue, Mar 6, 2012 at 11:29 PM, Mike Slinn <msl...@gmail.com> wrote:
    You see the code. What needs to change?

    The call to flatMap needs to provide a type for type parameter A (probably, it's late and I'm just wrapping up my travel plans)
     


    Mike

    --
    You received this message because you are subscribed to the Google Groups "Akka User List" group.
    To post to this group, send email to akka...@googlegroups.com.
    To unsubscribe from this group, send email to akka-user+unsubscribe@googlegroups.com.
    For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

    Michael Slinn

    unread,
    Mar 6, 2012, 5:41:32 PM3/6/12
    to akka...@googlegroups.com
    I think the code I showed fully specifies the types of all parameters. Anyone else know what Viktor might mean?

    Mike

    √iktor Ҡlang

    unread,
    Mar 6, 2012, 5:43:31 PM3/6/12
    to akka...@googlegroups.com
    On Tue, Mar 6, 2012 at 11:41 PM, Michael Slinn <msl...@gmail.com> wrote:
    I think the code I showed fully specifies the types of all parameters. Anyone else know what Viktor might mean?

    1. Future<Integer> f2 = f1.flatMap(new Mapper<String, Future<Integer>>() {
    2. public Future<Integer> apply(final String s) {
    3. return future(new Callable<Integer>() {
    4. public Integer call() {
    5. return s.length();
    6. }
    7. }, system.dispatcher());
    8. }
    9. });

     Where do you specify the _type parameter_ A to flatMap?

    Mike

    --
    You received this message because you are subscribed to the Google Groups "Akka User List" group.
    To view this discussion on the web visit https://groups.google.com/d/msg/akka-user/-/NWYXXlCQv6kJ.

    To post to this group, send email to akka...@googlegroups.com.
    To unsubscribe from this group, send email to akka-user+...@googlegroups.com.

    For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

    Michael Nascimento

    unread,
    Mar 6, 2012, 5:41:38 PM3/6/12
    to akka...@googlegroups.com
    Hi Mike,

    A non-complete snippet is really hard to parse when you have issues
    with generics. I am assuming from the compiler error that fla is a
    Future<Integer>, right? If that is the case, then Mapper's first type
    parameter must be Integer or a superclass and the API is correct.

    If that is not the case, please clarify.

    Regards,
    Michael Nascimento Santos
    http://threeten.sf.net/

    2012/3/6 √iktor Ҡlang <viktor...@gmail.com>:


    >
    >
    > On Tue, Mar 6, 2012 at 11:29 PM, Mike Slinn <msl...@gmail.com> wrote:
    >>
    >> You see the code. What needs to change?
    >
    >
    > The call to flatMap needs to provide a type for type parameter A (probably,
    > it's late and I'm just wrapping up my travel plans)
    >
    >>
    >>
    >>
    >> Mike
    >>
    >> --
    >> You received this message because you are subscribed to the Google Groups
    >> "Akka User List" group.
    >> To post to this group, send email to akka...@googlegroups.com.
    >> To unsubscribe from this group, send email to

    >> akka-user+...@googlegroups.com.


    >> For more options, visit this group at
    >> http://groups.google.com/group/akka-user?hl=en.
    >>
    >
    >
    >
    > --
    > Viktor Klang
    >
    > Akka Tech Lead
    > Typesafe - The software stack for applications that scale
    >
    > Twitter: @viktorklang
    >

    > --
    > You received this message because you are subscribed to the Google Groups
    > "Akka User List" group.
    > To post to this group, send email to akka...@googlegroups.com.
    > To unsubscribe from this group, send email to

    > akka-user+...@googlegroups.com.

    Peter Vlugter

    unread,
    Mar 6, 2012, 6:21:35 PM3/6/12
    to akka...@googlegroups.com

    Here's a direct translation from Scala to Java:

    final int a = 1;
    final int b = 2;
    final int c = 3;
    final int d = 4;
    final int e = 5;
    final int f = 6;

    Future<Integer> future4 = Futures.future(new ExpCalc(a, b), dispatcher).flatMap(new Mapper<Integer, Future<Integer>>() {
    public Future<Integer> apply(final Integer x) {
    return Futures.future(new ExpCalc(c, d), dispatcher).flatMap(new Mapper<Integer, Future<Integer>>() {
    public Future<Integer> apply(final Integer y) {
    return Futures.future(new ExpCalc(e, f), dispatcher).map(new Mapper<Integer, Integer>() {
    public Integer apply(final Integer z) {
    return x + y + z;
    }
    });
    }
    });
    }
    });

    Michael Slinn

    unread,
    Mar 6, 2012, 6:26:21 PM3/6/12
    to akka...@googlegroups.com
    Peter,

    That is exactly what I was trying to figure out. Thank you!

    Mike

    Jonas Bonér

    unread,
    Mar 7, 2012, 4:58:34 AM3/7/12
    to akka...@googlegroups.com

    Holy crap. That is ugly. Obfuscation build in - a feature.

    > --
    > You received this message because you are subscribed to the Google Groups "Akka User List" group.

    > To post to this group, send email to akka...@googlegroups.com.
    > To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
    > For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.
    >

    --
    Jonas Bonér
    CTO


    Typesafe - The software stack for applications that scale

    Phone: +46 733 777 123
    Twitter: @jboner

    Mike Slinn

    unread,
    Mar 7, 2012, 10:02:30 AM3/7/12
    to akka...@googlegroups.com
    Undeniably ugly, but it is correct. That was the missing piece I needed to complete the book.

    Mike

    Jonas Bonér

    unread,
    Mar 7, 2012, 10:13:27 AM3/7/12
    to akka...@googlegroups.com

    Great

    --
    Jonas Bonér
    CTO
    Typesafe - The software stack for applications that scale
    Phone: +46 733 777 123
    Twitter: @jboner

    Blog: letitcrash.com

    On Mar 7, 2012 4:03 PM, "Mike Slinn" <msl...@gmail.com> wrote:
    Undeniably ugly, but it is correct. That was the missing piece I needed to complete the book.

    Mike

    --
    Reply all
    Reply to author
    Forward
    0 new messages