[SIP-14] Futures and Promises

255 views
Skip to first unread message

Miller Heather

unread,
Jan 23, 2012, 5:05:06 AM1/23/12
to <scala-sips@googlegroups.com>
Hi all,

We're happy to announce the availability of the first of two SIPs which together constitute an overhaul of the scala.concurrent package.

This SIP covers an improved design for futures and promises-- powerful abstractions for composing asynchronous computations, in a non-blocking way. The SIP is available at:
http://docs.scala-lang.org/sips/pending/futures-promises.html

The redesign of the scala.concurrent package is a collaborative effort with members of the Akka team, Viktor Klang and Roland Kuhn. The design and implementation is based to a large extent on the futures in Akka 1.x. The overhaul of futures in Akka 2.0 is a first result of the work on this SIP.

Comments and discussion are welcomed!

Cheers,
Heather

Christos KK Loverdos

unread,
Jan 23, 2012, 5:30:44 AM1/23/12
to scala...@googlegroups.com
Hi Heather,


One thing that is not very clear, to me at least, is how registered callbacks actually compose. From the description

> The onComplete, onSuccess, and onFailure methods return the receiver (the future), which allows registering multiple callbacks by chaining invocations.


it feels like *all* applicable callbacks are executed.

Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?

Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of? Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally? Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?


Best,
Christos

--
__~O
-\ <, Christos KK Loverdos
(*)/ (*) http://stepsinscala.com


signature.asc

Eugene Burmako

unread,
Jan 23, 2012, 5:34:43 AM1/23/12
to scala...@googlegroups.com
Do you have a google doc or some facility for inline comments?

Eugene Burmako

unread,
Jan 23, 2012, 5:38:46 AM1/23/12
to scala-sips
I barely know a thing about asynchronous computations, but one
question immediately comes to my mind. How does this compare to
analogous functionality of .NET's BCL, namely to TPL and to upcoming
async/await feature of C# 5.0?

√iktor Ҡlang

unread,
Jan 23, 2012, 5:41:00 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 11:30 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Heather,

On Jan 23, 2012, at 12:05 PM, Miller Heather wrote:

> Hi all,
>
> We're happy to announce the availability of the first of two SIPs which together constitute an overhaul of the scala.concurrent package.
>
> This SIP covers an improved design for futures and promises-- powerful abstractions for composing asynchronous computations, in a non-blocking way. The SIP is available at:
> http://docs.scala-lang.org/sips/pending/futures-promises.html
>
> The redesign of the scala.concurrent package is a collaborative effort with members of the Akka team, Viktor Klang and Roland Kuhn. The design and implementation is based to a large extent on the futures in Akka 1.x. The overhaul of futures in Akka 2.0 is a first result of the work on this SIP.
>
> Comments and discussion are welcomed!
>
> Cheers,
> Heather


One thing that is not very clear, to me at least, is how registered callbacks actually compose. From the description

> The onComplete, onSuccess, and onFailure methods return the receiver (the future), which allows registering multiple callbacks by chaining invocations.


it feels like *all* applicable callbacks are executed.


Well of course, otherwise you cannot pass Futures into methods that may want to listen to the completion of it.
 
Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?

What's the value add of that?
 

Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of?

Good point, this should be made clear in the SIP. There is a happens-before relationship between adding a callback and calling that callback with the value of the future.

No, there aren't any races (that I know of).
 
Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally?

What do you mean?
 
Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?

No, in the case of a JVM failure it won't be called.

Cheers,

 


Best,
Christos

--
  __~O
 -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com







--
Viktor Klang

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

Twitter: @viktorklang

Christos KK Loverdos

unread,
Jan 23, 2012, 5:54:58 AM1/23/12
to scala...@googlegroups.com
Hi Victor,

Thanx for your prompt reply.

On Jan 23, 2012, at 12:41 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 11:30 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Heather,

On Jan 23, 2012, at 12:05 PM, Miller Heather wrote:

> Hi all,
>
> We're happy to announce the availability of the first of two SIPs which together constitute an overhaul of the scala.concurrent package.
>
> This SIP covers an improved design for futures and promises-- powerful abstractions for composing asynchronous computations, in a non-blocking way. The SIP is available at:
> http://docs.scala-lang.org/sips/pending/futures-promises.html
>
> The redesign of the scala.concurrent package is a collaborative effort with members of the Akka team, Viktor Klang and Roland Kuhn. The design and implementation is based to a large extent on the futures in Akka 1.x. The overhaul of futures in Akka 2.0 is a first result of the work on this SIP.
>
> Comments and discussion are welcomed!
>
> Cheers,
> Heather


One thing that is not very clear, to me at least, is how registered callbacks actually compose. From the description

> The onComplete, onSuccess, and onFailure methods return the receiver (the future), which allows registering multiple callbacks by chaining invocations.


it feels like *all* applicable callbacks are executed.


Well of course, otherwise you cannot pass Futures into methods that may want to listen to the completion of it.

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

 
Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?

What's the value add of that?

Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do. 

 

Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of?

Good point, this should be made clear in the SIP. There is a happens-before relationship between adding a callback and calling that callback with the value of the future.

No, there aren't any races (that I know of).
 
Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally?

What do you mean?

This just relates to the previous (and next) one, which you answered: I set the callback, this happens-before the completion, so (if the JVM does not crash etc etc) the callback will be always called.

 
Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?

No, in the case of a JVM failure it won't be called.

OK, so as long as the JVM is up and running, the futures lib guarantees that.


Cheers,

 


Best,
Christos

--
  __~O
 -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com







--
Viktor Klang

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

Twitter: @viktorklang



Best,
signature.asc

Jason Zaugg

unread,
Jan 23, 2012, 6:02:24 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Victor,

Thanx for your prompt reply.
Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

-jason 

√iktor Ҡlang

unread,
Jan 23, 2012, 6:03:36 AM1/23/12
to scala...@googlegroups.com
Hi Christos,

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Victor,

Thanx for your prompt reply.


You're welcome, this is how i roll.

On Jan 23, 2012, at 12:41 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 11:30 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Heather,

On Jan 23, 2012, at 12:05 PM, Miller Heather wrote:

> Hi all,
>
> We're happy to announce the availability of the first of two SIPs which together constitute an overhaul of the scala.concurrent package.
>
> This SIP covers an improved design for futures and promises-- powerful abstractions for composing asynchronous computations, in a non-blocking way. The SIP is available at:
> http://docs.scala-lang.org/sips/pending/futures-promises.html
>
> The redesign of the scala.concurrent package is a collaborative effort with members of the Akka team, Viktor Klang and Roland Kuhn. The design and implementation is based to a large extent on the futures in Akka 1.x. The overhaul of futures in Akka 2.0 is a first result of the work on this SIP.
>
> Comments and discussion are welcomed!
>
> Cheers,
> Heather


One thing that is not very clear, to me at least, is how registered callbacks actually compose. From the description

> The onComplete, onSuccess, and onFailure methods return the receiver (the future), which allows registering multiple callbacks by chaining invocations.


it feels like *all* applicable callbacks are executed.


Well of course, otherwise you cannot pass Futures into methods that may want to listen to the completion of it.

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

All will be executed if/when the future gets completed.
 

 
Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?

What's the value add of that?

Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do. 

The value of what's in the proposal hugely outweighs the complexity of the codebase, the code is very simple and elegant.
 

 

Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of?

Good point, this should be made clear in the SIP. There is a happens-before relationship between adding a callback and calling that callback with the value of the future.

No, there aren't any races (that I know of).
 
Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally?

What do you mean?

This just relates to the previous (and next) one, which you answered: I set the callback, this happens-before the completion, so (if the JVM does not crash etc etc) the callback will be always called.

 
Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?

No, in the case of a JVM failure it won't be called.

OK, so as long as the JVM is up and running, the futures lib guarantees that.

Depends on your definition of "guarantee". If the ExecutionContext fails to produce a thread for the callback to execute on, then it cannot execute the callback.

Cheese,

 


Cheers,

 


Best,
Christos

--
  __~O
 -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com







--
Viktor Klang

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

Twitter: @viktorklang



Best,
Christos
-- 
   __~O
  -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com




Philipp Haller

unread,
Jan 23, 2012, 6:43:59 AM1/23/12
to <scala-sips@googlegroups.com>
Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

However, I'm not sure that's the least surprising behavior, or the most flexible solution. It might be better to have onComplete return a new future, so that the future returned by `f onComplete {A}` would be failed in the above scenario. Moreover, we should then enforce a happens-before ordering among the callbacks (A < B < C where "<" = happens-before).

Cheers,
Philipp


Simon Ochsenreither

unread,
Jan 23, 2012, 6:46:31 AM1/23/12
to scala...@googlegroups.com
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

What's wrong with addSuppressed/getSuppressed?

Ismael Juma

unread,
Jan 23, 2012, 6:47:44 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 11:46 AM, Simon Ochsenreither <simon.och...@googlemail.com> wrote:
What's wrong with addSuppressed/getSuppressed? 

Only works in Java 7 and higher.

Best,
Ismael

Aleksandar Prokopec

unread,
Jan 23, 2012, 6:49:20 AM1/23/12
to scala-sips

>
> Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.
>

1) The `onComplete` call installs a callback to the future which is
invoked after the value in the future becomes available - callbacks
are always called after the value becomes available.

2) If the future value is already available (future is already
completed), then the execution context may either invoke the callback
right away on the same thread, or start a new task which will call the
callback with the value of the future. The only constraint is that it
must guarantee progress. This will typically mean that a new task will
be started to call the callback.

3) The order in which the callbacks are called if there are multiple
callbacks installed is undefined.

4) The future api guarantees that all callbacks are eventually called
if the future value (or exception within the future) is applicable to
them.


> Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do.

To separate concerns in that way, you can map a future that contains a
result of a computation using an identity function to produce several
other futures, on which you then install handlers:

val f = future { computation() }
val g1 = f map id
val g2 = f map id

g1 onComplete {
...
}

g2 onComplete {
...
}

You can do this, but we figured that it is more convenient in most
cases just to install handlers on the original future `f`.


> > No, there aren't any races (that I know of).
>

As Viktor already pointed out, no there should be no races here -
callbacks are called only after the future is completed.

Aleksandar Prokopec

unread,
Jan 23, 2012, 6:53:02 AM1/23/12
to scala-sips
The correct semantics should be: callbacks B and C are invoked
independently of whether A throws an exception. Since there is no
order defined in which these callbacks are invoked in the first place,
they should not be allowed to invalidate each other.
Furthermore, failing other callbacks due to one of the callbacks
failing might invalidate independent parts of the application - this
might violate separation of concerns.

So, I'd say, if in our current implementation an exception in A
discards B and C, we should fix our implementation.

Jason Zaugg

unread,
Jan 23, 2012, 6:55:49 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 12:49 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:
3) The order in which the callbacks are called if there are multiple
callbacks installed is undefined.

Is the implementation free to call them simultaneously?

-jason

Aleksandar Prokopec

unread,
Jan 23, 2012, 7:03:23 AM1/23/12
to scala...@googlegroups.com, Jason Zaugg
Good question.
In the current SIP and implementation - yes.

√iktor Ҡlang

unread,
Jan 23, 2012, 7:17:28 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 12:02 PM, Jason Zaugg wrote:

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

This is not the case in Akka, and I'd argue that it's completely wrong to do as above.
 

However, I'm not sure that's the least surprising behavior, or the most flexible solution. It might be better to have onComplete return a new future, so that the future returned by `f onComplete {A}` would be failed in the above scenario. Moreover, we should then enforce a happens-before ordering among the callbacks (A < B < C where "<" = happens-before).

Cheers,
Philipp


√iktor Ҡlang

unread,
Jan 23, 2012, 7:18:16 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:

Definitely not. That's be completely wrong and would make essentially everything serialized by default. You can achieve that effect with map id as proposed by Aleks.
 
Cheers,



Cheers,
Philipp


√iktor Ҡlang

unread,
Jan 23, 2012, 7:19:56 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 12:49 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:

>
> Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.
>

1) The `onComplete` call installs a callback to the future which is
invoked after the value in the future becomes available - callbacks
are always called after the value becomes available.

Indeed
 

2) If the future value is already available (future is already
completed), then the execution context may either invoke the callback
right away on the same thread, or start a new task which will call the
callback with the value of the future. The only constraint is that it
must guarantee progress. This will typically mean that a new task will
be started to call the callback.

I think the default should always to be to execute callbacks in other threads, read Havoc's excellent motivation for that: http://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/
 

3) The order in which the callbacks are called if there are multiple
callbacks installed is undefined.

Inded.
 

4) The future api guarantees that all callbacks are eventually called
if the future value (or exception within the future) is applicable to
them.

Indeed.
 


> Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do.

To separate concerns in that way, you can map a future that contains a
result of a computation using an identity function to produce several
other futures, on which you then install handlers:

val f = future { computation() }
val g1 = f map id
val g2 = f map id

g1 onComplete {
 ...
}

g2 onComplete {
 ...
}

You can do this, but we figured that it is more convenient in most
cases just to install handlers on the original future `f`.

Very good point.
 


> > No, there aren't any races (that I know of).
>

As Viktor already pointed out, no there should be no races here -
callbacks are called only after the future is completed.

√iktor Ҡlang

unread,
Jan 23, 2012, 7:20:19 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 12:53 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:
The correct semantics should be: callbacks B and C are invoked
independently of whether A throws an exception. Since there is no
order defined in which these callbacks are invoked in the first place,
they should not be allowed to invalidate each other.
Furthermore, failing other callbacks due to one of the callbacks
failing might invalidate independent parts of the application - this
might violate separation of concerns.


100% agree on this.
 
So, I'd say, if in our current implementation an exception in A
discards B and C, we should fix our implementation.

+Long.MaxValue
 


> Very good question.
> In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.
>
> However, I'm not sure that's the least surprising behavior, or the most flexible solution. It might be better to have onComplete return a new future, so that the future returned by `f onComplete {A}` would be failed in the above scenario. Moreover, we should then enforce a happens-before ordering among the callbacks (A < B < C where "<" = happens-before).
>
> Cheers,
> Philipp

Christos KK Loverdos

unread,
Jan 23, 2012, 7:22:12 AM1/23/12
to scala...@googlegroups.com
Hi Viktor and all,

(I have been writing this for some time now and I just saw a few subsequent emails in the thread)

On Jan 23, 2012, at 1:03 PM, √iktor Ҡlang wrote:

> Hi Christos,
>
> On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:
> Hi Victor,
>
> Thanx for your prompt reply.
>
>
> You're welcome, this is how i roll.
>
> On Jan 23, 2012, at 12:41 PM, √iktor Ҡlang wrote:
>
>>
>>
>> On Mon, Jan 23, 2012 at 11:30 AM, Christos KK Loverdos <love...@gmail.com> wrote:
>> Hi Heather,
>>
>> On Jan 23, 2012, at 12:05 PM, Miller Heather wrote:
>>
>> > Hi all,
>> >
>> > We're happy to announce the availability of the first of two SIPs which together constitute an overhaul of the scala.concurrent package.
>> >
>> > This SIP covers an improved design for futures and promises-- powerful abstractions for composing asynchronous computations, in a non-blocking way. The SIP is available at:
>> > http://docs.scala-lang.org/sips/pending/futures-promises.html
>> >
>> > The redesign of the scala.concurrent package is a collaborative effort with members of the Akka team, Viktor Klang and Roland Kuhn. The design and implementation is based to a large extent on the futures in Akka 1.x. The overhaul of futures in Akka 2.0 is a first result of the work on this SIP.
>> >
>> > Comments and discussion are welcomed!
>> >
>> > Cheers,
>> > Heather
>>
>>
>> One thing that is not very clear, to me at least, is how registered callbacks actually compose. From the description
>>
>> > The onComplete, onSuccess, and onFailure methods return the receiver (the future), which allows registering multiple callbacks by chaining invocations.
>>
>>
>> it feels like *all* applicable callbacks are executed.
>>
>>
>> Well of course, otherwise you cannot pass Futures into methods that may want to listen to the completion of it.
>
> Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.
>
> All will be executed if/when the future gets completed.


Let's make a thought experiment.

Let's say we have a future f, created at time t_0 and I make successive calls to onComplete with three closures A, B, C. In the mean time, some relevant background work will lead to the future getting either a value or an error. So, all the actions that take place are:

At t_1 > t_0 the call to f.onComplete(A) returns, so I assume A will be called OK when time comes
At t_2 > t_1 the call to f.onComplete(B) returns, so I assume B will be called OK when time comes
At t_3 > t_2 the future's value or exception has been computed and relevant state has been updated
At t_4 > t_3 the call to f.onComplete(C) returns, so I assume C will be called OK when time comes

Now the question is: What is the specification for the call to f.onComplete(C)? Will C be called? By assumption C does not happen-before the critical point where the future gets a value.

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far *and* the lifetime of a future is prolonged to infinity so as to accommodate for any subsequent onCompletion()s. Now, how does that interoperate with garbage collection?

A couple of points more:

- How about the above example but in a distributed setting (where time is not local, all the systemic "goodies" of a distributed setup applies, etc.). What is the specification for futures then? Does the library apply there too?

- When you discuss things in the spec, especially the onCompletion stuff, do you assume they are done in the same thread? Can the futures API be used concurrently? Does it make sense? Do we need to be aware of anything particular there?

>
>
>>
>> Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?
>>
>> What's the value add of that?
>
> Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do.
>
> The value of what's in the proposal hugely outweighs the complexity of the codebase, the code is very simple and elegant.

I am purely talking from a principles-point-of-view. Principles may help us make good questions and catch and *document* the exact intended behavior. Or to say it otherwise, I am purely driven by the so-far-spec-ed things and have not looked at any code (nor will I unless I feel I understand the semantics of what should any code represent).


>
>
>>
>>
>> Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of?
>>
>> Good point, this should be made clear in the SIP. There is a happens-before relationship between adding a callback and calling that callback with the value of the future.
>>
>> No, there aren't any races (that I know of).
>>
>> Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally?
>>
>> What do you mean?
>
> This just relates to the previous (and next) one, which you answered: I set the callback, this happens-before the completion, so (if the JVM does not crash etc etc) the callback will be always called.
>
>>
>> Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?
>>
>> No, in the case of a JVM failure it won't be called.
>
> OK, so as long as the JVM is up and running, the futures lib guarantees that.
>
> Depends on your definition of "guarantee". If the ExecutionContext fails to produce a thread for the callback to execute on, then it cannot execute the callback.

Yes, I meant guarantees modulo any systemic errors beyond the application's or library's control.

>
> Cheese,
> √
>
>
>>
>> Cheers,
>> √
>>
>>
>>
>> Best,
>> Christos
>>
>> --
>> __~O
>> -\ <, Christos KK Loverdos
>> (*)/ (*) http://stepsinscala.com
>>
>>
>>
>>
>>
>>
>>
>> --
>> Viktor Klang
>>
>> Akka Tech Lead
>> Typesafe - The software stack for applications that scale
>>
>> Twitter: @viktorklang
>>
>
>
> Best,
> Christos
> --
> __~O
> -\ <, Christos KK Loverdos
> (*)/ (*) http://stepsinscala.com
>
>
>
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>

As a last note, there is a bunch of terminology that needs to be clearly defined, so that we all agree on what to comment about and how to interpret things (e.g. "A future completes", "happens-before", etc etc).

√iktor Ҡlang

unread,
Jan 23, 2012, 7:28:04 AM1/23/12
to scala...@googlegroups.com

C will always be called when/if f is completed.
 

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far *and* the lifetime of a future is prolonged to infinity so as to accommodate for any subsequent onCompletion()s. Now, how does that interoperate with garbage collection?

As long as a strong reference to f exists, then the JVM cannot safely discard the callbacks. After a callback is executed, it [the callback] is eligible for GC.
 

A couple of points more:

 - How about the above example but in a distributed setting (where time is not local, all the systemic "goodies" of a distributed setup applies, etc.). What is the specification for futures then? Does the library apply there too?

Does the spec indicate this?
 

 - When you discuss things in the spec, especially the onCompletion stuff, do you assume they are done in the same thread? Can the futures API be used concurrently? Does it make sense? Do we need to be aware of anything particular there?

In my world a callback should _always_ be executed on another thread than the callers. see this link for more discussion on the topic: http://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/
 

>
>
>>
>> Also, it seems that a future spec-ed this way does some callback management itself. Wouldn't it be clearer from an API point of view to be able to register only one callback and leave and compositional semantics to the client code (i.e. the client specifies one callback no matter how complex this may be or what other callbacks have been used/composed to create it)?
>>
>> What's the value add of that?
>
> Separation of concerns comes to mind. Then, the futures has less things to manage, so it has potentially fewer bugs and concentrates on the one core thing it should do.
>
> The value of what's in the proposal hugely outweighs the complexity of the codebase, the code is very simple and elegant.

I am purely talking from  a principles-point-of-view. Principles may help us make good questions and catch and *document* the exact intended behavior. Or to say it otherwise, I am purely driven by the so-far-spec-ed things and have not looked at any code (nor will I unless I feel I understand the semantics of what should any code represent).

Futures have 3 states:

Pending(callbacks)
Success(value)
Failure(throwable)

that is the "maximum" complexity if we do not discuss code. For a deeper discussion then code needs to be included.
 


>
>
>>
>>
>> Another thing that I do not clearly see in the spec is how the definition of the callbacks interoperates with the actual/internal state of the future. For instance, when I say onComplete {...} are there any happens-before semantics (à la Java Memory Model) with respect to a) setting the callback and b) internally providing the actual state of the future. Are there any race conditions the client should be aware of?
>>
>> Good point, this should be made clear in the SIP. There is a happens-before relationship between adding a callback and calling that callback with the value of the future.
>>
>> No, there aren't any races (that I know of).
>>
>> Is there a safe way to make sure that I first register my callbacks and then any state is updated in the future internally?
>>
>> What do you mean?
>
> This just relates to the previous (and next) one, which you answered: I set the callback, this happens-before the completion, so (if the JVM does not crash etc etc) the callback will be always called.
>
>>
>> Is it guaranteed that if I set an onComplete callback that can handle any case (and so is a total function) then the callback will be called (when the future value completes)?
>>
>> No, in the case of a JVM failure it won't be called.
>
> OK, so as long as the JVM is up and running, the futures lib guarantees that.
>
> Depends on your definition of "guarantee". If the ExecutionContext fails to produce a thread for the callback to execute on, then it cannot execute the callback.

Yes, I meant guarantees modulo any systemic errors beyond the application's or library's control.

Then, yes.

Cheers,

 

Rex Kerr

unread,
Jan 23, 2012, 7:33:13 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 7:22 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Let's make a thought experiment.

Let's say we have a future f, created at time t_0 and I make successive calls to onComplete with three closures A, B, C. In the mean time, some relevant background work will lead to the future getting either a value or an error. So, all the actions that take place are:

At t_1 > t_0 the call to f.onComplete(A) returns, so I assume A will be called OK when time comes
At t_2 > t_1 the call to f.onComplete(B) returns, so I assume B will be called OK when time comes
At t_3 > t_2 the future's value or exception has been computed and relevant state has been updated
At t_4 > t_3 the call to f.onComplete(C) returns, so I assume C will be called OK when time comes

Now the question is: What is the specification for the call to f.onComplete(C)? Will C be called? By assumption C does not happen-before the critical point where the future gets a value.

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far

So the future keeps state.  What's the problem with that?
 
*and* the lifetime of a future is prolonged to infinity

Huh?  It only needs to keep a thread alive until it gets a value.

If you still have a reference, you can onComplete{...} and it will execute immediately using the stored value.  If you don't, the GC can eat it whenever it feels like it.  At least, that's how I hope it works.  Anything else would be weirdly unhelpful.

  --Rex

Christos KK Loverdos

unread,
Jan 23, 2012, 7:41:01 AM1/23/12
to scala...@googlegroups.com
On Jan 23, 2012, at 2:33 PM, Rex Kerr wrote:


On Mon, Jan 23, 2012 at 7:22 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Let's make a thought experiment.

Let's say we have a future f, created at time t_0 and I make successive calls to onComplete with three closures A, B, C. In the mean time, some relevant background work will lead to the future getting either a value or an error. So, all the actions that take place are:

At t_1 > t_0 the call to f.onComplete(A) returns, so I assume A will be called OK when time comes
At t_2 > t_1 the call to f.onComplete(B) returns, so I assume B will be called OK when time comes
At t_3 > t_2 the future's value or exception has been computed and relevant state has been updated
At t_4 > t_3 the call to f.onComplete(C) returns, so I assume C will be called OK when time comes

Now the question is: What is the specification for the call to f.onComplete(C)? Will C be called? By assumption C does not happen-before the critical point where the future gets a value.

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far

So the future keeps state.  What's the problem with that?

I do not remember starting any discussion by saying there is a problem. I am  taking time out of my consulting services and money-making process to help make a better SIP. So in this particular context, as a client of this future-library I *want* to know what is going on and if the future remembers my onComplete callbacks and if it remembers which ones it has called etc etc.

 
*and* the lifetime of a future is prolonged to infinity

Huh?  It only needs to keep a thread alive until it gets a value.

If you still have a reference, you can onComplete{...} and it will execute immediately using the stored value.  If you don't, the GC can eat it whenever it feels like it.  At least, that's how I hope it works.  Anything else would be weirdly unhelpful.

  --Rex


√iktor Ҡlang

unread,
Jan 23, 2012, 7:42:30 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 1:41 PM, Christos KK Loverdos <love...@gmail.com> wrote:

On Jan 23, 2012, at 2:33 PM, Rex Kerr wrote:


On Mon, Jan 23, 2012 at 7:22 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Let's make a thought experiment.

Let's say we have a future f, created at time t_0 and I make successive calls to onComplete with three closures A, B, C. In the mean time, some relevant background work will lead to the future getting either a value or an error. So, all the actions that take place are:

At t_1 > t_0 the call to f.onComplete(A) returns, so I assume A will be called OK when time comes
At t_2 > t_1 the call to f.onComplete(B) returns, so I assume B will be called OK when time comes
At t_3 > t_2 the future's value or exception has been computed and relevant state has been updated
At t_4 > t_3 the call to f.onComplete(C) returns, so I assume C will be called OK when time comes

Now the question is: What is the specification for the call to f.onComplete(C)? Will C be called? By assumption C does not happen-before the critical point where the future gets a value.

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far

So the future keeps state.  What's the problem with that?

I do not remember starting any discussion by saying there is a problem. I am  taking time out of my consulting services and money-making process to help make a better SIP. So in this particular context, as a client of this future-library I *want* to know what is going on and if the future remembers my onComplete callbacks and if it remembers which ones it has called etc etc.

A callback is only stored as long as the future is yet to be completed, it is discarded as soon as it's been called.
 

 
*and* the lifetime of a future is prolonged to infinity

Huh?  It only needs to keep a thread alive until it gets a value.

If you still have a reference, you can onComplete{...} and it will execute immediately using the stored value.  If you don't, the GC can eat it whenever it feels like it.  At least, that's how I hope it works.  Anything else would be weirdly unhelpful.

  --Rex


-- 
   __~O
  -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com




Christos KK Loverdos

unread,
Jan 23, 2012, 7:47:49 AM1/23/12
to scala...@googlegroups.com
Hi Viktor,

Overall, thanx for the discussion.

Cool.

 

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far *and* the lifetime of a future is prolonged to infinity so as to accommodate for any subsequent onCompletion()s. Now, how does that interoperate with garbage collection?

As long as a strong reference to f exists, then the JVM cannot safely discard the callbacks. After a callback is executed, it [the callback] is eligible for GC.
 

A couple of points more:

 - How about the above example but in a distributed setting (where time is not local, all the systemic "goodies" of a distributed setup applies, etc.). What is the specification for futures then? Does the library apply there too?

Does the spec indicate this?

In any case, let's just be explicit about this.

 

 - When you discuss things in the spec, especially the onCompletion stuff, do you assume they are done in the same thread? Can the futures API be used concurrently? Does it make sense? Do we need to be aware of anything particular there?

In my world a callback should _always_ be executed on another thread than the callers. see this link for more discussion on the topic: http://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/

Sure. I was talking about calling onComplete on the same future on different threads.

Simon Ochsenreither

unread,
Jan 23, 2012, 7:50:28 AM1/23/12
to scala...@googlegroups.com
I already wrote something on the SIP site, but because of the tradition of disappearing comments and because I read a bit of the sources, I'll comment here:

First of all: In general, the proposal looks good. Would be interesting to know what the migration story is. Will all those third-party implementations move to the "default one" or are there reasons to keep a separate one (except for backward compatibility)?

But I strongly dislike one detail: Duration.

There are multiple reasons a few about the code and a few with the strategy:
  • The API doesn't follow the style guide (finite_?)
  • The API has duplicate methods (for Java)
  • ... which also don't follow the Java style guide
  • The class has strong dependencies to java.util.concurrent.TimeUnit
  • The proposed package scala.util doesn't make sense
  • The class duplicates functionality expected to arrive in Java 8

I just think we shouldn't go down the way of adding some random "utility" classes for date/time to the standard library. Java did that and we all know how that ended.

  • Either we should think of having a decent date/time/unit library in Scala (which would make a lot of sense).
  • Or use the already existing functionality existing, instead of inventing our own.
  • Or try to leave out the Duration stuff and have a look at more lightweight alternatives.

In my opinion, there is just a lack of coherent vision regarding everything people can't write a thesis about.

Thanks and bye,

Simon

Philipp Haller

unread,
Jan 23, 2012, 7:50:47 AM1/23/12
to <scala-sips@googlegroups.com>
On Jan 23, 2012, at 1:17 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 12:02 PM, Jason Zaugg wrote:

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

This is not the case in Akka, and I'd argue that it's completely wrong to do as above.

As I already said, I don't agree with this behavior, hence my alternative proposal.

Actually, the implementation I described contained a bug causing this (surprising) behavior. We just fixed it.

Philipp

--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University



Aleksandar Prokopec

unread,
Jan 23, 2012, 7:55:24 AM1/23/12
to scala...@googlegroups.com, Christos KK Loverdos

>
> Let's make a thought experiment.
>
> Let's say we have a future f, created at time t_0 and I make successive calls to onComplete with three closures A, B, C. In the mean time, some relevant background work will lead to the future getting either a value or an error. So, all the actions that take place are:
>
> At t_1> t_0 the call to f.onComplete(A) returns, so I assume A will be called OK when time comes
> At t_2> t_1 the call to f.onComplete(B) returns, so I assume B will be called OK when time comes
> At t_3> t_2 the future's value or exception has been computed and relevant state has been updated
> At t_4> t_3 the call to f.onComplete(C) returns, so I assume C will be called OK when time comes
>
> Now the question is: What is the specification for the call to f.onComplete(C)? Will C be called? By assumption C does not happen-before the critical point where the future gets a value.
>
> From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified.

We can, as I've written in the previous post - if a callback is
registered after the value is available, it will be called after it is
registered. The happens-before relationship still exists:
- the callback is registered after the value becomes available
- the callback is called after it is registered
-> transitively - the callback is called after the value becomes available


> *UNLESS* the future keeps state about which callbacks it has called so far *and* the lifetime of a future is prolonged to infinity so as to accommodate for any subsequent onCompletion()s. Now, how does that interoperate with garbage collection?

To register a callback on a future, you need a reference to the future.
If there is no reference to the future anywhere in the program, then you
will not be able to register a callback. Also, the GC will in this case
collect the future object.
If there is a possibility of installing the callback, then there must be
a reference to the future object, so you cannot GC the future. But
having a reference to an object implies that it cannot be garbage
collected anyway.

If there is no reference to the future object, all the registered
callbacks will be called eventually. Once they do, the future will be
garbage collected.


>
> A couple of points more:
>
> - How about the above example but in a distributed setting (where time is not local, all the systemic "goodies" of a distributed setup applies, etc.). What is the specification for futures then? Does the library apply there too?

We do not have distributed futures yet, nor have we defined their semantics.

> - When you discuss things in the spec, especially the onCompletion stuff, do you assume they are done in the same thread?

No.

> Can the futures API be used concurrently?

Yes.

> Does it make sense?

Yes.

> Do we need to be aware of anything particular there?

You only have to be aware of the Java memory model, publication, etc. if
you are doing mutable side-effects from within the future body. For example:

var x = 1
future {
x = 2
}
future {
if (x == 2) x = 3
}

Here you would have to make x volatile.

If you are only using futures in a dataflow/functional way - use
referentially transparent maps etc., then you don't have to worry about
this.

>

√iktor Ҡlang

unread,
Jan 23, 2012, 8:01:07 AM1/23/12
to scala...@googlegroups.com
Hi Christos,

On Mon, Jan 23, 2012 at 1:47 PM, Christos KK Loverdos <love...@gmail.com> wrote:
Hi Viktor,

Overall, thanx for the discussion.

You're very welcome, discussion is good. :-)
 

Very!
 

 

From the above and without loss of generality it is obvious that we cannot guarantee the execution of all onComplete closures, since this way the futures library should wait to complete until the very last closure is specified. But clearly this leads to infinite time or non-termination. *UNLESS* the future keeps state about which callbacks it has called so far *and* the lifetime of a future is prolonged to infinity so as to accommodate for any subsequent onCompletion()s. Now, how does that interoperate with garbage collection?

As long as a strong reference to f exists, then the JVM cannot safely discard the callbacks. After a callback is executed, it [the callback] is eligible for GC.
 

A couple of points more:

 - How about the above example but in a distributed setting (where time is not local, all the systemic "goodies" of a distributed setup applies, etc.). What is the specification for futures then? Does the library apply there too?

Does the spec indicate this?

In any case, let's just be explicit about this.

The spec has nothing to do with a distributed setting. Of course things become a bit trickier with a distributed setting since you can't rely on GC to clean up your mess. For Akka we support remote Futures through the Ask/? operation, which takes a deadline/timeout after which Akka will complete the future with an AskTimeoutExcpetion, which is a subclass to TimeoutExcpetion, so things looking for timeouts see it as a timeout.
 

 

 - When you discuss things in the spec, especially the onCompletion stuff, do you assume they are done in the same thread? Can the futures API be used concurrently? Does it make sense? Do we need to be aware of anything particular there?

In my world a callback should _always_ be executed on another thread than the callers. see this link for more discussion on the topic: http://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/

Sure. I was talking about calling onComplete on the same future on different threads.

No, I think you mean executing the callbacks on the completers thread, or?
 

√iktor Ҡlang

unread,
Jan 23, 2012, 8:03:09 AM1/23/12
to scala...@googlegroups.com

You mean the current impl in Akka drops the callbacks if there's an exception in them?
 

Philipp

--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University



Christos KK Loverdos

unread,
Jan 23, 2012, 8:08:02 AM1/23/12
to scala...@googlegroups.com
No, I did not originally think about executing the callbacks. You thought about that and contributed it to the discussion :) I just thought about calling onComplete from different threads.

√iktor Ҡlang

unread,
Jan 23, 2012, 8:09:58 AM1/23/12
to scala...@googlegroups.com
"No, I did not originally think about executing the callbacks. You thought about that and contributed it to the discussion :) I just thought about calling onComplete from different threads."

Calling onComplete from different threads is completely safe in all sort of ways.

Aleksandar Prokopec

unread,
Jan 23, 2012, 8:11:11 AM1/23/12
to scala...@googlegroups.com, Christos KK Loverdos

>> Does the spec indicate this?
>
> In any case, let's just be explicit about this.
>

Agreed - the SIP will be updated from useful points gathered here.

Philipp Haller

unread,
Jan 23, 2012, 8:12:27 AM1/23/12
to <scala-sips@googlegroups.com>
On Jan 23, 2012, at 2:03 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 1:50 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 1:17 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 12:02 PM, Jason Zaugg wrote:

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

This is not the case in Akka, and I'd argue that it's completely wrong to do as above.

As I already said, I don't agree with this behavior, hence my alternative proposal.

Actually, the implementation I described contained a bug causing this (surprising) behavior. We just fixed it.

You mean the current impl in Akka drops the callbacks if there's an exception in them?

No, someone introduced a bug when migrating Akka's implementation into the default implementation package. Details in the commit log. ;-)

Philipp

Aleksandar Prokopec

unread,
Jan 23, 2012, 8:13:23 AM1/23/12
to scala...@googlegroups.com, Simon Ochsenreither

Java 8 is not due for another several years, and we're not even on 7 yet.
While I agree that a unified Duration class would be a good thing, perhaps all these blocking calls should take nanos or millis, and have implicit conversions from Duration classes to nanos or millis.
This way, when the One True Duration class pops into existence, we can just create another implicit conversion.

√iktor Ҡlang

unread,
Jan 23, 2012, 8:17:00 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 2:12 PM, Philipp Haller <philipp...@epfl.ch> wrote:

On Jan 23, 2012, at 2:03 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 1:50 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 1:17 PM, √iktor Ҡlang wrote:



On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 12:02 PM, Jason Zaugg wrote:

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

This is not the case in Akka, and I'd argue that it's completely wrong to do as above.

As I already said, I don't agree with this behavior, hence my alternative proposal.

Actually, the implementation I described contained a bug causing this (surprising) behavior. We just fixed it.

You mean the current impl in Akka drops the callbacks if there's an exception in them?

No, someone introduced a bug when migrating Akka's implementation into the default implementation package. Details in the commit log. ;-)

I think we should definitely have a showdown regarding the callbacks. I am firmly in the camp that says that your callbacks shouldn't mess with mine.
 

Philipp



 

Philipp

--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University






--
Viktor Klang

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

Twitter: @viktorklang


--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University



Aleksandar Prokopec

unread,
Jan 23, 2012, 8:16:58 AM1/23/12
to scala...@googlegroups.com, √iktor Ҡlang

No, the current impl is ok with regards to that.
However, the current impl will not execute all the callbacks if one of the callbacks of the future blocks forever (see the Promise.tryComplete method). We should fix this. We want all the callbacks executed eventually, even if some of them decide to block forever.

Aleksandar Prokopec

unread,
Jan 23, 2012, 8:17:15 AM1/23/12
to scala...@googlegroups.com, Philipp Haller

;)

√iktor Ҡlang

unread,
Jan 23, 2012, 8:17:42 AM1/23/12
to scala...@googlegroups.com, Simon Ochsenreither
On Mon, Jan 23, 2012 at 2:13 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:

Java 8 is not due for another several years, and we're not even on 7 yet.
While I agree that a unified Duration class would be a good thing, perhaps all these blocking calls should take nanos or millis, and have implicit conversions from Duration classes to nanos or millis.
This way, when the One True Duration class pops into existence, we can just create another implicit conversion.

If we switch to a long, it needs to be nanos, which procludes blocking more than like a 1000 days.
 



On 1/23/12 1:50 PM, Simon Ochsenreither wrote:
I already wrote something on the SIP site, but because of the tradition of disappearing comments and because I read a bit of the sources, I'll comment here:

First of all: In general, the proposal looks good. Would be interesting to know what the migration story is. Will all those third-party implementations move to the "default one" or are there reasons to keep a separate one (except for backward compatibility)?

But I strongly dislike one detail: Duration.

There are multiple reasons a few about the code and a few with the strategy:
  • The API doesn't follow the style guide (finite_?)
  • The API has duplicate methods (for Java)
  • ... which also don't follow the Java style guide
  • The class has strong dependencies to java.util.concurrent.TimeUnit
  • The proposed package scala.util doesn't make sense
  • The class duplicates functionality expected to arrive in Java 8

I just think we shouldn't go down the way of adding some random "utility" classes for date/time to the standard library. Java did that and we all know how that ended.

  • Either we should think of having a decent date/time/unit library in Scala (which would make a lot of sense).
  • Or use the already existing functionality existing, instead of inventing our own.
  • Or try to leave out the Duration stuff and have a look at more lightweight alternatives.

In my opinion, there is just a lack of coherent vision regarding everything people can't write a thesis about.

Thanks and bye,

Simon


√iktor Ҡlang

unread,
Jan 23, 2012, 8:18:57 AM1/23/12
to Aleksandar Prokopec, scala...@googlegroups.com


2012/1/23 Aleksandar Prokopec <aleksanda...@gmail.com>


No, the current impl is ok with regards to that.
However, the current impl will not execute all the callbacks if one of the callbacks of the future blocks forever (see the Promise.tryComplete method). We should fix this. We want all the callbacks executed eventually, even if some of them decide to block forever.

you mean you're running the callbacks on the completer? If so, that's a big no-no, we used to do that, and you don't want to place that burden on the producer.
 



You mean the current impl in Akka drops the callbacks if there's an exception in them?
 


Christos KK Loverdos

unread,
Jan 23, 2012, 8:20:23 AM1/23/12
to scala...@googlegroups.com
On Jan 23, 2012, at 3:09 PM, √iktor Ҡlang wrote:

"No, I did not originally think about executing the callbacks. You thought about that and contributed it to the discussion :) I just thought about calling onComplete from different threads."

Beware.....Putting stuff out of context is dangerous :) :) OK. I remember where I made that particular remark.


Calling onComplete from different threads is completely safe in all sort of ways.

Good to know. Let's have that in the SIP as well.


--
Viktor Klang

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

Twitter: @viktorklang

Simon Ochsenreither

unread,
Jan 23, 2012, 8:22:06 AM1/23/12
to scala...@googlegroups.com
Does it matter?

Check the version and use it if available. Done.

Aleksandar Prokopec

unread,
Jan 23, 2012, 8:22:07 AM1/23/12
to √iktor Ҡlang, scala...@googlegroups.com

No, we're not running callbacks on the completer - we do the same thing
you do:

executor dispatchTask {
() => cs.foreach(f => notifyCompleted(f, value))
}

private final def notifyCompleted(func: Either[Throwable, T] =>
Any, result: Either[Throwable, T]) {
try {
func(result)
} catch {
case e => e.printStackTrace()
}
}

cs being a callback sequence. Since this is a single task, the callbacks
are executed in order - if one callbacks runs forever, the subsequent
ones are never completed.

Message has been deleted

Simon Ochsenreither

unread,
Jan 23, 2012, 8:25:29 AM1/23/12
to scala...@googlegroups.com, Simon Ochsenreither
Imho just using Longs would be sensible.

√iktor Ҡlang

unread,
Jan 23, 2012, 8:27:20 AM1/23/12
to Aleksandar Prokopec, scala...@googlegroups.com


2012/1/23 Aleksandar Prokopec <aleksanda...@gmail.com>


No, we're not running callbacks on the completer - we do the same thing you do:

         executor dispatchTask {
           () => cs.foreach(f => notifyCompleted(f, value))
         }

   private final def notifyCompleted(func: Either[Throwable, T] => Any, result: Either[Throwable, T]) {
     try {
       func(result)
     } catch {
       case e => e.printStackTrace()
     }
   }

cs being a callback sequence. Since this is a single task, the callbacks are executed in order - if one callbacks runs forever, the subsequent ones are never completed.

Ah, great, with the exclusion of callbacks that signal that they're going to do blocking prior to going into hogging-mode.
However, when we gets Dougs new goodies going we should consider submitting all callbacks for execution asynchronously.
What's currently being done is an optimization.

Cheers,

 




you mean you're running the callbacks on the completer? If so, that's a big no-no, we used to do that, and you don't want to place that burden on the producer.

Philipp Haller

unread,
Jan 23, 2012, 8:27:24 AM1/23/12
to <scala-sips@googlegroups.com>
On Jan 23, 2012, at 1:18 PM, √iktor Ҡlang wrote:

On Mon, Jan 23, 2012 at 12:43 PM, Philipp Haller <philipp...@epfl.ch> wrote:
On Jan 23, 2012, at 12:02 PM, Jason Zaugg wrote:

On Mon, Jan 23, 2012 at 11:54 AM, Christos KK Loverdos <love...@gmail.com> wrote:

Probably I was not clear. If I say onComplete {A} onComplete {B} onComplete {C} in a chained invocation, will all of {A}, {B}, {C} tried? Only the last one? The first one? This is not clear to me from the SIP.

I'm assuming all three, but it should be explicitly mentioned. Perhaps more importantly, what's the behaviour if the callbacks raise an exception?

Very good question.
In our current implementation, if A throws an exception, besides printing the stack trace, it discards B and C.

However, I'm not sure that's the least surprising behavior, or the most flexible solution. It might be better to have onComplete return a new future, so that the future returned by `f onComplete {A}` would be failed in the above scenario. Moreover, we should then enforce a happens-before ordering among the callbacks (A < B < C where "<" = happens-before).

Definitely not. That's be completely wrong and would make essentially everything serialized by default. You can achieve that effect with map id as proposed by Aleks.

Of course, serializing all callbacks is problematic when you try to get concurrency by having multiple concurrent clients read from the same future. So, we should definitely keep concurrent callbacks, probably as the default (as it is now- "your callbacks don't mess with mine").

However, for a single client who wants to install multiple callbacks there should also be a way to enforce ordering among these callbacks, for example to support try-finally style code. One approach that we just discussed with Alex would be to use a projection for that:

   fut.ordered.onSuccess { A } onComplete { B }

So, if there is success, execute A and then B. If there is no success, only execute B.

Cheers,
Philipp

√iktor Ҡlang

unread,
Jan 23, 2012, 8:29:01 AM1/23/12
to scala...@googlegroups.com

Isn't ordering achieved by using subsequent maps?

Cheers,

 

Cheers,
Philipp

--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University



Simon Ochsenreither

unread,
Jan 23, 2012, 8:29:23 AM1/23/12
to scala...@googlegroups.com, Simon Ochsenreither
My concern is not only the API of Future/Promise but also the addition of some half-baked date/time class, additionally the idea of putting it into scala.util makes it an even more insane.

√iktor Ҡlang

unread,
Jan 23, 2012, 8:31:53 AM1/23/12
to scala...@googlegroups.com, Simon Ochsenreither


On Mon, Jan 23, 2012 at 2:29 PM, Simon Ochsenreither <simon.och...@googlemail.com> wrote:
My concern is not only the API of Future/Promise but also the addition of some half-baked date/time class, additionally the idea of putting it into scala.util makes it an even more insane.

Did you miss the discussion we've just tried to have where we're discussing moving to Longs for the timeout? Or what?

Aleksandar Prokopec

unread,
Jan 23, 2012, 8:32:14 AM1/23/12
to √iktor Ҡlang, scala...@googlegroups.com
Agreed - we should push all tasks to a task queue available to everybody
to guarantee completion.

My point was merely that the current optimization may block forever. :)

√iktor Ҡlang

unread,
Jan 23, 2012, 8:32:43 AM1/23/12
to Aleksandar Prokopec, scala...@googlegroups.com


2012/1/23 Aleksandar Prokopec <aleksanda...@gmail.com>

Agreed - we should push all tasks to a task queue available to everybody to guarantee completion.

My point was merely that the current optimization may block forever. :)

Do it :-)
 



Ah, great, with the exclusion of callbacks that signal that they're going to do blocking prior to going into hogging-mode.
However, when we gets Dougs new goodies going we should consider submitting all callbacks for execution asynchronously.
What's currently being done is an optimization.

Cheers,


Philipp Haller

unread,
Jan 23, 2012, 8:59:48 AM1/23/12
to <scala-sips@googlegroups.com>
On Jan 23, 2012, at 2:29 PM, √iktor Ҡlang wrote:
Of course, serializing all callbacks is problematic when you try to get concurrency by having multiple concurrent clients read from the same future. So, we should definitely keep concurrent callbacks, probably as the default (as it is now- "your callbacks don't mess with mine").

However, for a single client who wants to install multiple callbacks there should also be a way to enforce ordering among these callbacks, for example to support try-finally style code. One approach that we just discussed with Alex would be to use a projection for that:

   fut.ordered.onSuccess { A } onComplete { B }

So, if there is success, execute A and then B. If there is no success, only execute B.

Isn't ordering achieved by using subsequent maps?

Yes, I think that's what one could do:

   fut map { res => Right(A) } recover { e => Left(e) } map { either => B }

It's just not very nice. We could consider adding a combinator for that.

√iktor Ҡlang

unread,
Jan 23, 2012, 9:04:45 AM1/23/12
to scala...@googlegroups.com

"andThen"?
 

Cheers,
Philipp

--
Co-author, "Actors in Scala" (Artima Inc, 2011)
Postdoc, EPFL and Stanford University



Ismael Juma

unread,
Jan 23, 2012, 9:10:54 AM1/23/12
to scala...@googlegroups.com
On Mon, Jan 23, 2012 at 1:13 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:
Java 8 is not due for another several years

Not that it matters for this discussion, but Java 8 is due next year.

Best,
Ismael

√iktor Ҡlang

unread,
Jan 23, 2012, 9:13:12 AM1/23/12
to scala...@googlegroups.com

OTOH that doesn't help for Scala.NET nor the people who want to use Scala with Java < 8
 

Best,
Ismael

Ismael Juma

unread,
Jan 23, 2012, 9:42:58 AM1/23/12
to scala...@googlegroups.com
2012/1/23 √iktor Ҡlang <viktor...@gmail.com>

Not that it matters for this discussion, but Java 8 is due next year.

OTOH that doesn't help for Scala.NET nor the people who want to use Scala with Java < 8

Of course. That is why I said that it doesn't matter for this discussion. My email was simply a factual correction.

Best,
Ismael

√iktor Ҡlang

unread,
Jan 23, 2012, 9:45:26 AM1/23/12
to scala...@googlegroups.com

See my response as a clarification of your response.

V

Michael Slinn

unread,
Jan 24, 2012, 3:03:06 AM1/24/12
to scala...@googlegroups.com
  1. Seems that some of akka.dispatch will be moved or replicated into scala.concurrent for Scala 2.10. Is the intention is to move classes and methods instead of replicating them, or will the Akka futures API forward to scala.concurrent?
  2. The SIP introduction mentions collections of futures, but the rest of the document only discusses single futures.  Which Future-related classes and traits will be moved or forwarded from Akka to scala.concurrent?
  3. Will there be other changes made to the API, or will the impact on existing programs that use Akka futures be limited to changing imports? 
Mike

√iktor Ҡlang

unread,
Jan 24, 2012, 3:27:49 AM1/24/12
to scala...@googlegroups.com, Akka User List
Hi Michael,

I'd say that's a question for the akka ml :)

On Tue, Jan 24, 2012 at 9:03 AM, Michael Slinn <msl...@gmail.com> wrote:
  1. Seems that some of akka.dispatch will be moved or replicated into scala.concurrent for Scala 2.10. Is the intention is to move classes and methods instead of replicating them, or will the Akka futures API forward to scala.concurrent?
The idea is to harmonize the two so that in the end there's only the standard library Futures, which should be virtually identical before the switch.

  1. The SIP introduction mentions collections of futures, but the rest of the document only discusses single futures.  Which Future-related classes and traits will be moved or forwarded from Akka to scala.concurrent?
Virtually all of it. The new Akka Future API for 2.0 is harmonized with the proposal.

  1. Will there be other changes made to the API, or will the impact on existing programs that use Akka futures be limited to changing imports? 
I have yet to gain the ability to see into the future, but the goal is to have it as simple as a package-switch.

Cheers,


 
Mike

Christos KK Loverdos

unread,
Jan 24, 2012, 3:33:49 AM1/24/12
to Aleksandar Prokopec, scala...@googlegroups.com
Aleksandar,

On Jan 23, 2012, at 3:11 PM, Aleksandar Prokopec wrote:

>
>>> Does the spec indicate this?
>>
>> In any case, let's just be explicit about this.
>>
>
> Agreed - the SIP will be updated from useful points gathered here.
>
>
>

Thank you for taking all the points I have raised and dealing with them.

The reason I insist(ed), is that I view this SIP very fundamental for current and future libraries. This SIP should be a proper specification for the futures, IMHO.

Rock on.
Christos

√iktor Ҡlang

unread,
Jan 24, 2012, 3:36:38 AM1/24/12
to scala...@googlegroups.com, Aleksandar Prokopec
On Tue, Jan 24, 2012 at 9:33 AM, Christos KK Loverdos <love...@gmail.com> wrote:
Aleksandar,

On Jan 23, 2012, at 3:11 PM, Aleksandar Prokopec wrote:

>
>>> Does the spec indicate this?
>>
>> In any case, let's just be explicit about this.
>>
>
> Agreed - the SIP will be updated from useful points gathered here.
>
>
>

Thank you for taking all the points I have raised and dealing with them.

The reason I insist(ed), is that I view this SIP very fundamental for current and future libraries. This SIP should be a proper specification for the futures, IMHO.

You are very right, and you've brought up some very good points that we need to clarify and formalize.
 

Rock on.

I'm dead sure he will.

Cheers,

 
Christos
--
  __~O
 -\ <,       Christos KK Loverdos
(*)/ (*)      http://stepsinscala.com




Aleksandar Prokopec

unread,
Jan 24, 2012, 3:45:06 AM1/24/12
to Christos KK Loverdos, scala...@googlegroups.com
On 1/24/12 9:33 AM, Christos KK Loverdos wrote:
> Aleksandar,
>
> On Jan 23, 2012, at 3:11 PM, Aleksandar Prokopec wrote:
>
>>>> Does the spec indicate this?
>>> In any case, let's just be explicit about this.
>>>
>> Agreed - the SIP will be updated from useful points gathered here.
>>
>>
>>
> Thank you for taking all the points I have raised and dealing with them.
You're welcome.

Cheers,
Alex

Aleksandar Prokopec

unread,
Jan 30, 2012, 11:32:10 AM1/30/12
to scala...@googlegroups.com
As part of the Future SIP improvement process, we are currently renaming some of the methods in the Future trait.

Current ideas are as follows:

1. In addition to the `recover` method which essentially maps a future with a throwable into a future with a regular value, we decided to have an additional method which also maps a future with a throwable into a future with a regular value but using another future. Here is the signature:

  def tryRecover[U >: T](pf: PartialFunction[Throwable, Future[U]]): Future[U]

The relationship between `recover` and this new method is analogous to that between `map` and `flatMap`.

Current idea is to call it `tryRecover`.
As this might indicate there is some `try-catching` involved with calling this method, another option is to call it `flatRecover`.
Ideally, we do not wish to introduce another name (having already introduced `recover`), but the new name should somehow signify that it is using another future to complete this one in the case of a failure, and that if the other future also fails, then the resulting future will also fail.

2. We have previously defined a method called `orElse` on the Future.

  def orElse[U >: T](that: Future[U]): Future[U]

This method is related to the same method on the `Option` type - if this future fails, then the resulting future is completed with the result of `that` future. We deliberately avoided a by-name parameter for `that`, as that would create subtle differences in the way `orElse` is called:

  future { op1() } orElse future { op2() }
 
  // would not be the same as:
  val f = future { op2() }
  future { op1() } orElse f

Ideally, we always want the second semantics - the second future should be started asynchronously, and not only once and if the first future fails.

Since the signature differs to that in the Option type, which does have the by-name parameter here, one current suggestion is to rename it to `or`.

3. There are some methods on the Future companion object:

  def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]]) (implicit cbf: CanBuildFrom[Coll[Future[A]], A, Coll[A]]): Future[Coll[T]]
  def any[T](futures: Traversable[Future[T]]): Future[T]

The first method takes a collection of futures, and returns a future with the collection of the results once all the futures complete. This method is called `sequence` in Akka futures.
The second method takes a collection of futures and returns a future holding the result of the first completed future. This method is called `firstCompletedOf` in Akka futures. We've discussed recently that sometimes we may want to get the first _successful_ future instead.
One idea was to introduce `firstSuccessfulOf` or `firstSuccess` as an additional method.
Another suggested approach was to introduce a predicate parameter on the `firstCompleted(Of)`.

Thoughts and ideas?

Thanks,
Alex




Rex Kerr

unread,
Jan 30, 2012, 11:59:55 AM1/30/12
to scala...@googlegroups.com
On Mon, Jan 30, 2012 at 11:32 AM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:
As part of the Future SIP improvement process, we are currently renaming some of the methods in the Future trait.

Current ideas are as follows:

1. In addition to the `recover` method which essentially maps a future with a throwable into a future with a regular value, we decided to have an additional method which also maps a future with a throwable into a future with a regular value but using another future. Here is the signature:

  def tryRecover[U >: T](pf: PartialFunction[Throwable, Future[U]]): Future[U]

The relationship between `recover` and this new method is analogous to that between `map` and `flatMap`.

Current idea is to call it `tryRecover`.
As this might indicate there is some `try-catching` involved with calling this method, another option is to call it `flatRecover`.
Ideally, we do not wish to introduce another name (having already introduced `recover`), but the new name should somehow signify that it is using another future to complete this one in the case of a failure, and that if the other future also fails, then the resulting future will also fail.

I don't really like flatRecover, as it provides amazingly little insight into what is going on (without more careful deliberation than is really nice to ask for when scanning methods).

I would prefer recoverX to xRecover also, because that will put it near recover alphabetically (and make the flow of the program more rapidly apparent at a glance).

Of those you suggested, I guess I like tryRecover the best (though personally I'd probably just override the recover name if the compiler could handle the type inference).

Of recoverX names, I suppose recoverableBy gets the point across, though it's kind of clumsy.
 

2. We have previously defined a method called `orElse` on the Future.

  def orElse[U >: T](that: Future[U]): Future[U]

This method is related to the same method on the `Option` type - if this future fails, then the resulting future is completed with the result of `that` future. We deliberately avoided a by-name parameter for `that`, as that would create subtle differences in the way `orElse` is called:

  future { op1() } orElse future { op2() }
 
  // would not be the same as:
  val f = future { op2() }
  future { op1() } orElse f

Ideally, we always want the second semantics - the second future should be started asynchronously, and not only once and if the first future fails.

Since the signature differs to that in the Option type, which does have the by-name parameter here, one current suggestion is to rename it to `or`.

Ouch.  Lazy evaluation is the expectation here for pretty much everything or-based.  Simply using `or` is not enough to highlight the non-laziness.  Why do you want non-laziness anyway?  Seems like you want

  future { op1() } and { op2() } and { op(3) } takeFirst

if you want to highlight the simultaneity.  Or maybe

  futures( op1(), op2(), op3() ).firstSuccess

vs.

  futures( op1(), op2(), op3() ).soonestSuccess
 

3. There are some methods on the Future companion object:

  def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]]) (implicit cbf: CanBuildFrom[Coll[Future[A]], A, Coll[A]]): Future[Coll[T]]
  def any[T](futures: Traversable[Future[T]]): Future[T]

The first method takes a collection of futures, and returns a future with the collection of the results once all the futures complete. This method is called `sequence` in Akka futures.
The second method takes a collection of futures and returns a future holding the result of the first completed future. This method is called `firstCompletedOf` in Akka futures. We've discussed recently that sometimes we may want to get the first _successful_ future instead.
One idea was to introduce `firstSuccessfulOf` or `firstSuccess` as an additional method.
Another suggested approach was to introduce a predicate parameter on the `firstCompleted(Of)`.

Shouldn't the first success be the default?  And maybe you want to use "soonest" instead of "first" to disambiguate the order of the futures in the list from the order of completion in time?

Then you have soonest(blah) and soonestCompleted(blah).

A method called `any` should provide no guarantees of any sort about which future is returned.  It can pick whichever it feels like.  Otherwise it isn't actually `any`, it's `oneOfAccordingToSomeRule`.

  --Rex

√iktor Ҡlang

unread,
Jan 30, 2012, 12:11:39 PM1/30/12
to scala...@googlegroups.com
On Mon, Jan 30, 2012 at 5:59 PM, Rex Kerr <ich...@gmail.com> wrote:
On Mon, Jan 30, 2012 at 11:32 AM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:
As part of the Future SIP improvement process, we are currently renaming some of the methods in the Future trait.

Current ideas are as follows:

1. In addition to the `recover` method which essentially maps a future with a throwable into a future with a regular value, we decided to have an additional method which also maps a future with a throwable into a future with a regular value but using another future. Here is the signature:

  def tryRecover[U >: T](pf: PartialFunction[Throwable, Future[U]]): Future[U]

The relationship between `recover` and this new method is analogous to that between `map` and `flatMap`.

Current idea is to call it `tryRecover`.
As this might indicate there is some `try-catching` involved with calling this method, another option is to call it `flatRecover`.
Ideally, we do not wish to introduce another name (having already introduced `recover`), but the new name should somehow signify that it is using another future to complete this one in the case of a failure, and that if the other future also fails, then the resulting future will also fail.

I don't really like flatRecover, as it provides amazingly little insight into what is going on (without more careful deliberation than is really nice to ask for when scanning methods).

I would prefer recoverX to xRecover also, because that will put it near recover alphabetically (and make the flow of the program more rapidly apparent at a glance).

Of those you suggested, I guess I like tryRecover the best (though personally I'd probably just override the recover name if the compiler could handle the type inference).

Of recoverX names, I suppose recoverableBy gets the point across, though it's kind of clumsy.

I prefer tryRecover, but "recoverUsing" or "recoverWith" could also work.
Yeah, "any" sounds a bit too generic.

Cheers,
 


  --Rex

Aleksandar Prokopec

unread,
Jan 30, 2012, 12:18:02 PM1/30/12
to scala...@googlegroups.com, Rex Kerr

I don't really like flatRecover, as it provides amazingly little insight into what is going on (without more careful deliberation than is really nice to ask for when scanning methods).

I would prefer recoverX to xRecover also, because that will put it near recover alphabetically (and make the flow of the program more rapidly apparent at a glance).

Of those you suggested, I guess I like tryRecover the best (though personally I'd probably just override the recover name if the compiler could handle the type inference).

Of recoverX names, I suppose recoverableBy gets the point across, though it's kind of clumsy.
 

Perhaps - recoverWith? It does bear an analogy to the Promise.completeWith(Future).




Since the signature differs to that in the Option type, which does have the by-name parameter here, one current suggestion is to rename it to `or`.

Ouch.  Lazy evaluation is the expectation here for pretty much everything or-based.  Simply using `or` is not enough to highlight the non-laziness.  Why do you want non-laziness anyway? 


Because we expect that typically one wants to start another future asynchronously before the current one completes to make use of parallelism.
Otherwise, `orElse` becomes a mere shorthand for the previous method.

I agree that due to the usual non-lazyness semantics are different here.



3. There are some methods on the Future companion object:

  def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]]) (implicit cbf: CanBuildFrom[Coll[Future[A]], A, Coll[A]]): Future[Coll[T]]
  def any[T](futures: Traversable[Future[T]]): Future[T]

The first method takes a collection of futures, and returns a future with the collection of the results once all the futures complete. This method is called `sequence` in Akka futures.
The second method takes a collection of futures and returns a future holding the result of the first completed future. This method is called `firstCompletedOf` in Akka futures. We've discussed recently that sometimes we may want to get the first _successful_ future instead.
One idea was to introduce `firstSuccessfulOf` or `firstSuccess` as an additional method.
Another suggested approach was to introduce a predicate parameter on the `firstCompleted(Of)`.

Shouldn't the first success be the default? 

It seems like a common use case - but then it acts as a shorthand and has the same semantics as `Future.find[T](Traversable[Future[T]])(T => Boolean)` with an always-true predicate.


And maybe you want to use "soonest" instead of "first" to disambiguate the order of the futures in the list from the order of completion in time?

Perhaps.
Btw, another idea proposed was `select`.


A method called `any` should provide no guarantees of any sort about which future is returned.  It can pick whichever it feels like.  Otherwise it isn't actually `any`, it's `oneOfAccordingToSomeRule`.

Good point.



Rex Kerr

unread,
Jan 30, 2012, 1:28:54 PM1/30/12
to Aleksandar Prokopec, scala...@googlegroups.com
On Mon, Jan 30, 2012 at 12:18 PM, Aleksandar Prokopec <aleksanda...@gmail.com> wrote:


Since the signature differs to that in the Option type, which does have the by-name parameter here, one current suggestion is to rename it to `or`.

Ouch.  Lazy evaluation is the expectation here for pretty much everything or-based.  Simply using `or` is not enough to highlight the non-laziness.  Why do you want non-laziness anyway? 


Because we expect that typically one wants to start another future asynchronously before the current one completes to make use of parallelism.
Otherwise, `orElse` becomes a mere shorthand for the previous method.

I agree that due to the usual non-lazyness semantics are different here.

So use totally different method names.  Identical or similar method names with dramatically different consequences are a guaranteed way to generate confusion.

Using either `or` or `orElse` is no better (possibly even worse!) than using `?` or `~`.  The problem is that even though you can write

  future { try { op1() } catch{ case Whatever => op2() } }

it's much more awkward than writing

  future { op1() } or { op2() }

and so a non-negligible fraction of people will likely routinely use the latter when they mean the former and then write angry blog posts about how Scala has crazy processor usage for simple logical tasks with futures.  (Scala futures are broken, blah blah blah.)

  --Rex

Aleksandar Prokopec

unread,
Jan 31, 2012, 5:27:19 AM1/31/12
to Rex Kerr, scala...@googlegroups.com


Because we expect that typically one wants to start another future asynchronously before the current one completes to make use of parallelism.
Otherwise, `orElse` becomes a mere shorthand for the previous method.

I agree that due to the usual non-lazyness semantics are different here.

So use totally different method names.  Identical or similar method names with dramatically different consequences are a guaranteed way to generate confusion.

Using either `or` or `orElse` is no better (possibly even worse!) than using `?` or `~`.  The problem is that even though you can write

  future { try { op1() } catch{ case Whatever => op2() } }

it's much more awkward than writing

  future { op1() } or { op2() }

and so a non-negligible fraction of people will likely routinely use the latter when they mean the former and then write angry blog posts about how Scala has crazy processor usage for simple logical tasks with futures.  (Scala futures are broken, blah blah blah.)


Perhaps `alongWith` then instead of `or` or `orElse`?



-- 
Aleksandar Prokopec,
Doctoral Assistant
LAMP, IC, EPFL
http://people.epfl.ch/aleksandar.prokopec

√iktor Ҡlang

unread,
Jan 31, 2012, 5:31:47 AM1/31/12
to scala...@googlegroups.com, Rex Kerr
Or == someFuture tryRecover { case _ => otherFuture } ?
 




-- 
Aleksandar Prokopec,
Doctoral Assistant
LAMP, IC, EPFL
http://people.epfl.ch/aleksandar.prokopec

Aleksandar Prokopec

unread,
Jan 31, 2012, 5:33:16 AM1/31/12
to Rex Kerr, scala...@googlegroups.com
Though that wouldn't communicate that the other future's result is only taken into account if the first one fails.
Another idea I've just had is:

val f = future { ... }
val g = future { ... }
f otherwise g

√iktor Ҡlang

unread,
Jan 31, 2012, 5:34:58 AM1/31/12
to scala...@googlegroups.com, Rex Kerr
f fallbackTo g

Aleksandar Prokopec

unread,
Jan 31, 2012, 5:36:24 AM1/31/12
to scala...@googlegroups.com, √iktor Ҡlang, Rex Kerr

Yes, `or` is currently in Akka the same thing `orElse` is in scala.concurrent, if I understood correctly. And it can be expressed using `tryRecover`, with an additional boilerplate of having to write `case` and construct an additional closure.
The question is if we want to have this operation at all, since it's a shorthand for what you've written below.

Aleksandar Prokopec

unread,
Jan 31, 2012, 5:37:03 AM1/31/12
to scala...@googlegroups.com, √iktor Ҡlang, Rex Kerr


Though that wouldn't communicate that the other future's result is only taken into account if the first one fails.
Another idea I've just had is:

val f = future { ... }
val g = future { ... }
f otherwise g

f fallbackTo g


+1

√iktor Ҡlang

unread,
Jan 31, 2012, 6:18:16 AM1/31/12
to Aleksandar Prokopec, scala...@googlegroups.com, Rex Kerr


2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>



Though that wouldn't communicate that the other future's result is only taken into account if the first one fails.
Another idea I've just had is:

val f = future { ... }
val g = future { ... }
f otherwise g

f fallbackTo g


Can we have some consensus here? I think users are starting to think I'm nuts changing this all the time.
 

+1



-- 
Aleksandar Prokopec,
Doctoral Assistant
LAMP, IC, EPFL
http://people.epfl.ch/aleksandar.prokopec

Aleksandar Prokopec

unread,
Jan 31, 2012, 7:34:12 AM1/31/12
to √iktor Ҡlang, scala...@googlegroups.com, Rex Kerr
On 1/31/12 12:18 PM, √iktor Ҡlang wrote:


2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>


Though that wouldn't communicate that the other future's result is only taken into account if the first one fails.
Another idea I've just had is:

val f = future { ... }
val g = future { ... }
f otherwise g

f fallbackTo g


Can we have some consensus here? I think users are starting to think I'm nuts changing this all the time.
 

I vote for `fallbackTo`.

Miller Heather

unread,
Jan 31, 2012, 10:22:58 AM1/31/12
to <scala-sips@googlegroups.com>, √iktor Ҡlang, Rex Kerr
Agree on `fallbackTo`-- I think it makes the semantics perfectly clear.
(Though `otherwise` is also quite nice.)

Regarding the `tryRecover` thing- I agree with the point that we previously arrived at--> we shouldn't introduce a new name. And it would be nice if, in Scaladoc, the methods would appear next to each other, as Rex pointed out. However, given those constraints, the only thing I can think of is:

`recoverAndFlatten`

The thing about `recoverWith` is that, while it's similar to `completeWith`, you need to be aware of `completeWith` to be able to infer what `recoverWith` might do. If you came across `recoverWith` in some code somewhere without parameter types (i.e. f recoverWith pf), it's not quite obvious what it does. `completeWith` on the other hand is a bit more obvious, given its context in Promise. 

That said, in an effort to keep with the recoverX convention, might work:

`recoverWithFuture`
 
…Which is a bit long, and has its issues, but at least it's more obvious than `tryRecover` (which seems too much like a try/catch)


Cheers, 
Heather


√iktor Ҡlang

unread,
Jan 31, 2012, 10:30:39 AM1/31/12
to Miller Heather, <scala-sips@googlegroups.com>, Rex Kerr


2012/1/31 Miller Heather <heather...@epfl.ch>


On Jan 31, 2012, at 1:34 PM, Aleksandar Prokopec wrote:

On 1/31/12 12:18 PM, √iktor Ҡlang wrote:


2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>


Though that wouldn't communicate that the other future's result is only taken into account if the first one fails.
Another idea I've just had is:

val f = future { ... }
val g = future { ... }
f otherwise g

f fallbackTo g


Can we have some consensus here? I think users are starting to think I'm nuts changing this all the time.
 

I vote for `fallbackTo`.

Agree on `fallbackTo`-- I think it makes the semantics perfectly clear.
(Though `otherwise` is also quite nice.)

Alright, so we all agree on fallbackTo?
 

Regarding the `tryRecover` thing- I agree with the point that we previously arrived at--> we shouldn't introduce a new name. And it would be nice if, in Scaladoc, the methods would appear next to each other, as Rex pointed out. However, given those constraints, the only thing I can think of is:

`recoverAndFlatten`

The thing about `recoverWith` is that, while it's similar to `completeWith`, you need to be aware of `completeWith` to be able to infer what `recoverWith` might do. If you came across `recoverWith` in some code somewhere without parameter types (i.e. f recoverWith pf), it's not quite obvious what it does. `completeWith` on the other hand is a bit more obvious, given its context in Promise. 

That said, in an effort to keep with the recoverX convention, might work:

`recoverWithFuture`
 
…Which is a bit long, and has its issues, but at least it's more obvious than `tryRecover` (which seems too much like a try/catch)

recoverUsing?
 


Cheers, 
Heather


Aleksandar Prokopec

unread,
Jan 31, 2012, 11:35:24 AM1/31/12
to scala...@googlegroups.com, √iktor Ҡlang, Miller Heather, Rex Kerr

Agree on `fallbackTo`-- I think it makes the semantics perfectly clear.
(Though `otherwise` is also quite nice.)

Alright, so we all agree on fallbackTo?

I agree.




√iktor Ҡlang

unread,
Jan 31, 2012, 11:45:42 AM1/31/12
to Aleksandar Prokopec, scala...@googlegroups.com, Miller Heather, Rex Kerr


2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>
Alright, renamed and pushed to Akka master.


So what's the consensus on flatRecover?

Aleksandar Prokopec

unread,
Jan 31, 2012, 11:48:50 AM1/31/12
to √iktor Ҡlang, scala...@googlegroups.com, Miller Heather, Rex Kerr
On 1/31/12 5:45 PM, √iktor Ҡlang wrote:


2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>

Agree on `fallbackTo`-- I think it makes the semantics perfectly clear.
(Though `otherwise` is also quite nice.)

Alright, so we all agree on fallbackTo?

I agree.

Alright, renamed and pushed to Akka master.


So what's the consensus on flatRecover?

I would personally go for `recoverWith`.

Derek Williams

unread,
Jan 31, 2012, 11:59:15 AM1/31/12
to scala...@googlegroups.com, √iktor Ҡlang, Miller Heather, Rex Kerr
2012/1/31 Aleksandar Prokopec <aleksanda...@gmail.com>

I prefer 'recoverFlat' or 'recoverWith'.

Also semi-related, a 'flatten' method would help in many of these cases as well (unless it's already squeaked in there when I wasn't looking).

--
Derek Williams

√iktor Ҡlang

unread,
Jan 31, 2012, 12:01:17 PM1/31/12
to Derek Williams, scala...@googlegroups.com, Miller Heather, Rex Kerr


2012/1/31 Derek Williams <de...@fyrie.net>
I vote for recoverWith
 


--
Derek Williams

√iktor Ҡlang

unread,
Jan 31, 2012, 3:54:43 PM1/31/12
to Derek Williams, scala...@googlegroups.com, Miller Heather, Rex Kerr
So is there consensus for recoverWith?

2012/1/31 √iktor Ҡlang <viktor...@gmail.com>

Mike Slinn

unread,
Jan 31, 2012, 10:32:38 AM1/31/12
to scala...@googlegroups.com
recoverUsing?
Sounds like a 12 step program. There will be some cruel jokes made.

Mike

--

Michael Slinn     +1-415-367-3789    •    Twitter: mslinn    •    GitHub    •    LinkedIn    •    Scala
http://micronauticsresearch.com
http://slinnbooks.com



√iktor Ҡlang

unread,
Feb 3, 2012, 10:45:37 AM2/3/12
to scala...@googlegroups.com
recoverWith has been chosen. Let the bikeshed dry
logo-300x91.png
Reply all
Reply to author
Forward
0 new messages