Scala Future and Typed execution context

378 views
Skip to first unread message

Sadache Aldrobi

unread,
Aug 8, 2012, 1:40:56 AM8/8/12
to scala...@googlegroups.com
Hello all,

This is probably too late for such topics but I find it often very useful if Futures would carry execution context types on them in some way.

If we could have trait Future[+T,-E <: ExecutionContext] then its callback functions won't accept anything upper than that particular ExecutionContext.

So you would write

using(someExecutionContext) { implicit ec =>

map the future and do whatever


}

Of course the E type would default to ExecutionContext so everything would work fine, but there are a lot of cases you want to be specific and not accidentally use a globally imported one.

For instance you could have in a web framework an ExecutionContaxt that is bound to the life of the request, and once the request is handed over you can choose to stop the execution on that particular EC.

This provides a safe way of scoping and grouping tasks. I could put together a pull-request if it helps to see clearer what I mean.

Thanks,
Sadek

--
www.sadekdrobi.com
ʎdoɹʇuǝ

√iktor Ҡlang

unread,
Aug 8, 2012, 6:24:57 AM8/8/12
to scala...@googlegroups.com
Hi Sadek!

Thanks for giving us feedback!

On Wed, Aug 8, 2012 at 7:40 AM, Sadache Aldrobi <sadek...@gmail.com> wrote:
Hello all,

This is probably too late for such topics but I find it often very useful if Futures would carry execution context types on them in some way.

If we could have trait Future[+T,-E <: ExecutionContext] then its callback functions won't accept anything upper than that particular ExecutionContext.

So you would write

using(someExecutionContext) { implicit ec =>

How does it improve over:

{
  implicit val ec = someExecutionContext
  …
}

Cheers,
 

map the future and do whatever


}

Of course the E type would default to ExecutionContext so everything would work fine, but there are a lot of cases you want to be specific and not accidentally use a globally imported one.

For instance you could have in a web framework an ExecutionContaxt that is bound to the life of the request, and once the request is handed over you can choose to stop the execution on that particular EC.

This provides a safe way of scoping and grouping tasks. I could put together a pull-request if it helps to see clearer what I mean.

Thanks,
Sadek

--
www.sadekdrobi.com
ʎdoɹʇuǝ



--
Viktor Klang

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

Twitter: @viktorklang

Sadache Aldrobi

unread,
Aug 8, 2012, 8:22:44 AM8/8/12
to scala...@googlegroups.com
Hi Viktor,

On Wed, Aug 8, 2012 at 12:24 PM, √iktor Ҡlang <viktor...@gmail.com> wrote:
Hi Sadek!

Thanks for giving us feedback!

On Wed, Aug 8, 2012 at 7:40 AM, Sadache Aldrobi <sadek...@gmail.com> wrote:
Hello all,

This is probably too late for such topics but I find it often very useful if Futures would carry execution context types on them in some way.

If we could have trait Future[+T,-E <: ExecutionContext] then its callback functions won't accept anything upper than that particular ExecutionContext.

So you would write

using(someExecutionContext) { implicit ec =>

How does it improve over:

{
  implicit val ec = someExecutionContext
  …
}

It improves over

import someGlobalContext;

val f = {

  implicit val ec = someExecutionContext

  Future(..).map(...)


}.map(...)

This will work even if the above import is accidental

Whereas:

import someGlobalContext;

val f = {

  implicit val ec = MyExecutionContext

  ScopedFuture[Int,MyExecutionContext](..).map(...)


}.map(...)

won't accidentally compile.

Of course the API could be nicer to not require explicitly typing T but that is a different matter. So in a given web framework I could have:

Action { request =>

  ForRequest.future(...).map(...).map(...)


}

won't compile no matter what imports I've got until I make:

Action { implicit request =>

  ForRequest.future(...).map(...).map(...)


}

Of course ForRequest takes the request as an implicit parameter and gives a future with a unique type of context which is available in the scope.
 

Cheers,
 

map the future and do whatever


}

Of course the E type would default to ExecutionContext so everything would work fine, but there are a lot of cases you want to be specific and not accidentally use a globally imported one.

For instance you could have in a web framework an ExecutionContaxt that is bound to the life of the request, and once the request is handed over you can choose to stop the execution on that particular EC.

This provides a safe way of scoping and grouping tasks. I could put together a pull-request if it helps to see clearer what I mean.

Thanks,
Sadek

--
www.sadekdrobi.com
ʎdoɹʇuǝ



--
Viktor Klang

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

Twitter: @viktorklang




--
www.sadekdrobi.com
ʎdoɹʇuǝ

Havoc Pennington

unread,
Aug 9, 2012, 10:58:01 AM8/9/12
to scala...@googlegroups.com
If you were to go down this road, it seems like you may as well just
go back to the EC-is-a-property-of-Future situation, which is
basically "the EC is not customizable"
Here's some code for that btw:
https://github.com/havocp/scala/commit/d6929a9125cbaad5b30f1892fc328e3916ab144b

I mean, why have an implicit EC if it has to be of the particular type
"per-request Play EC" anyway, you're really pretty much saying it has
to have a specific value, not just a specific type? In a given spot
there's only going to be one instance of "per-request Play EC".

It could make sense for Play to set this kind of policy since Play is
defining so much stuff for people already. In the above commit
FutureWithExecutionContext has a conversion back to Future which
allows people to override the EC if they really want to.
"futureWithEC.future.onComplete(callback)(myEC)"

I guess in theory people could make their own subtypes of "per-request
Play EC" that might do something like decorate the request EC with
debug tracing. Binding the EC to the future does restrict that kind of
customization. But you could allow it to be customized elsewhere, for
example maybe allow setting an EC factory on the Application instance.

For a per-request EC in Play, perhaps there's another strategy: try to
be sure the EC you really want is always imported... maybe put
"implicit def requestExecutionContext" in some typically-imported
package, and/or make some always-used APIs require your EC subclass to
be available implicitly... the idea would be that the correct EC is
already imported, so if someone accidentally imports another one,
there would be an ambiguity error. The only way to use a custom EC
would be to explicitly get rid of the Play per-request EC with "import
playEC => _"

Future[T, EC] seems like one of those cases (which I've often
encountered) where it might be nice conceptually to type-parameterize
something but it will create a problem because people will have to
write out or otherwise "deal with" that type parameter ....

Since you can never specify only some of the type parameters for a
class or method, if any of them are ambiguous or you for any reason
need to specify any of them, you always have to specify all of them.
So it's hard to have type parameters that are interesting in distinct
situations. Some code might want to specify T and some might want to
specify EC but all code will have to deal with both. I don't know,
I've found that I have to sort of pick which parameterization is most
useful for a given class or method and omit other potential
genericizations for sanity.

Just some offhand thoughts.

I might pursue the "try hard to be sure the Play per-request EC is
always imported so there's ambiguity if another one also is" idea
first just because it would be so much simpler (if it works) and would
not introduce a bunch of new API or API changes.

Both FutureWithExecutionContext and Future[T, EC] effectively fragment
Future into multiple incompatible kinds of Future, which for sure
increases complexity for app developers.

Havoc

Sadache Aldrobi

unread,
Aug 20, 2012, 11:51:48 AM8/20/12
to scala...@googlegroups.com
On Thu, Aug 9, 2012 at 4:58 PM, Havoc Pennington <h...@pobox.com> wrote:
If you were to go down this road, it seems like you may as well just
go back to the EC-is-a-property-of-Future situation, which is
basically "the EC is not customizable"
 Here's some code for that btw:
https://github.com/havocp/scala/commit/d6929a9125cbaad5b30f1892fc328e3916ab144b

I mean, why have an implicit EC if it has to be of the particular type
"per-request Play EC" anyway, you're really pretty much saying it has
to have a specific value, not just a specific type? In a given spot
there's only going to be one instance of "per-request Play EC".

It could make sense for Play to set this kind of policy since Play is
defining so much stuff for people already. In the above commit
FutureWithExecutionContext has a conversion back to Future which
allows people to override the EC if they really want to.
"futureWithEC.future.onComplete(callback)(myEC)"

It seems to me that it is a general purpose functionality and the fact that you already implemented something like that only proves the point...
Otherwise we might end up again each having his/her own Future type (which don't extend Future), something we are trying to avoid by putting Futures in scala.
Implicit conversions are the last resort, at least to me. If this is an extensibility that is required by frameworks, then it seems like a good idea to integrate it than leaving it accidental.

At any point you can quit a given EC by simply explicitly change the EC type (to Nothing for a any), this way user will be declaring explicitly that he is willing to go out of control, which is really good.

Having this type + an ad hoc forkable EC can allow sophisticated, cancelable, traceable execution trees. 
 

I guess in theory people could make their own subtypes of "per-request
Play EC" that might do something like decorate the request EC with
debug tracing. Binding the EC to the future does restrict that kind of
customization. But you could allow it to be customized elsewhere, for
example maybe allow setting an EC factory on the Application instance.

For a per-request EC in Play, perhaps there's another strategy: try to
be sure the EC you really want is always imported... maybe put
"implicit def requestExecutionContext" in some typically-imported
package, and/or make some always-used APIs require your EC subclass to
be available implicitly... the idea would be that the correct EC is
already imported, so if someone accidentally imports another one,
there would be an ambiguity error. The only way to use a custom EC
would be to explicitly get rid of the Play per-request EC with "import
playEC => _"

Future[T, EC] seems like one of those cases (which I've often
encountered) where it might be nice conceptually to type-parameterize
something but it will create a problem because people will have to
write out or otherwise "deal with" that type parameter ....


I guess for when it is not used, it will really not surface, exactly how Option[Nothing] doesn't surface in None.
 
Since you can never specify only some of the type parameters for a
class or method, if any of them are ambiguous or you for any reason
need to specify any of them, you always have to specify all of them.

Again you can completely hide it with, for instance, a sub trait.
 
So it's hard to have type parameters that are interesting in distinct
situations. Some code might want to specify T and some might want to
specify EC but all code will have to deal with both. I don't know,
I've found that I have to sort of pick which parameterization is most
useful for a given class or method and omit other potential
genericizations for sanity.

Just some offhand thoughts.

I might pursue the "try hard to be sure the Play per-request EC is
always imported so there's ambiguity if another one also is" idea
first just because it would be so much simpler (if it works) and would
not introduce a bunch of new API or API changes.

Both FutureWithExecutionContext and Future[T, EC] effectively fragment
Future into multiple incompatible kinds of Future, which for sure
increases complexity for app developers.

Havoc

Thanks Havoc,

Sadek

--
www.sadekdrobi.com
ʎdoɹʇuǝ

Havoc Pennington

unread,
Aug 22, 2012, 5:22:03 AM8/22/12
to scala...@googlegroups.com
On Mon, Aug 20, 2012 at 11:51 AM, Sadache Aldrobi <sadek...@gmail.com> wrote:
>
> Again you can completely hide it with, for instance, a sub trait.
>

Maybe Future[T] is the sub trait, and we could add some kind of
supertype Something[T, EC] ?

I don't know what to call the supertype though.

Havoc

Sadache Aldrobi

unread,
Aug 26, 2012, 4:03:10 PM8/26/12
to scala...@googlegroups.com
SuperFuture :)
 

Havoc



--
www.sadekdrobi.com
ʎdoɹʇuǝ
Reply all
Reply to author
Forward
0 new messages