Future : Implementation of impl.Future(body) not versatile enough

92 views
Skip to first unread message

Martin Senne

unread,
Mar 24, 2014, 6:54:49 PM3/24/14
to scala-l...@googlegroups.com
Hi Victor and hi to all the other future gurus,

the extensibility of ExecutionContext becomes impossible due to the concrete implementation inside impl.Future, given as

 def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.prepare.execute(runnable)
    runnable.promise.future
  }

No change to extends that behaviour. As it is fine to have a PromiseCompletingRunnable in certain circumstances, this does not hold for ALL situations .... exactly HERE, extensibility is wanted.
So, the current implementation given in (scala.concurrent.impl) is not sufficient for extensibility.

What ways can you image, to introduce custom "Runnable"s ......
Do you have a different extension strategy in mind?

Let us now ..... looking forward for your answer!

Marvin and Martin



Martin Senne

unread,
Mar 24, 2014, 6:56:27 PM3/24/14
to scala-l...@googlegroups.com
No change = No chance  ..... or course ......

√iktor Ҡlang

unread,
Mar 24, 2014, 7:01:36 PM3/24/14
to scala-l...@googlegroups.com
Hi Martin,

Can you give an example of your perceived problem?


On Mon, Mar 24, 2014 at 11:56 PM, Martin Senne <martin...@googlemail.com> wrote:
No change = No chance  ..... or course ......

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

———————
Viktor Klang
Chief Architect - Typesafe

Twitter: @viktorklang

Martin Senne

unread,
Mar 24, 2014, 7:17:13 PM3/24/14
to scala-l...@googlegroups.com
Hi Victor,

the main focus of our problem is, that it is impossible to "inject" a custom Runnable to the apply(...) method of the impl.Future.

This PromiseCompletingRunnable (as a Runnable) is fine for certain situations,

We need a clean way to extend
- the behavior of scala.concurrent.impl.Future to allow custom Runnables or instead
- plug in a "mightier" esecution context.

Especially our problem comes to evidence, when we try to implementaiton a custom remote execution context...... without a chance, since the Runnable creation stays behind the scenes and is by no way influencable.


Cheers,

Martin

√iktor Ҡlang

unread,
Mar 24, 2014, 7:28:03 PM3/24/14
to scala-l...@googlegroups.com
Hi Martin,


On Tue, Mar 25, 2014 at 12:17 AM, Martin Senne <martin...@googlemail.com> wrote:
Hi Victor,

the main focus of our problem is, that it is impossible to "inject" a custom Runnable to the apply(...) method of the impl.Future.

implicit val ec = new ExecutionContext {
  override def execute(runnable: Runnable): Unit = otherEC.prepare.execute(new CustomRunnable(runnable))
  …
}

val f = Future(computation)

BUT Future.apply is just one of many ways of constructing a Future. So doing what you suggest wouldn't be a catch-all solution.
 

This PromiseCompletingRunnable (as a Runnable) is fine for certain situations,

We need a clean way to extend
- the behavior of scala.concurrent.impl.Future to allow custom Runnables or instead
- plug in a "mightier" esecution context.

Does the solution I showed above address that?
 

Especially our problem comes to evidence, when we try to implementaiton a custom remote execution context...... without a chance, since the Runnable creation stays behind the scenes and is by no way influencable.

You can influence it as I showed above, in execute. Or am I missing something?

Martin Senne

unread,
Mar 24, 2014, 8:00:06 PM3/24/14
to scala-l...@googlegroups.com
Hi Voctor,

sorry, but I have to be very picky


private[concurrent] object Future {
  class PromiseCompletingRunnable[T](body: => T) extends Runnable {
    val promise = new Promise.DefaultPromise[T]()

    override def run() = {
      promise complete {
        try Success(body) catch { case NonFatal(e) => Failure(e) }

      }
    }
  }

  def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.prepare.execute(runnable)
    runnable.promise.future
  }
}


That is the excerpt from Future.apply(...) .....

=> With the given implementation of Future.apply(..), there is no chance to exchange the Runnable by a custom Ruannable except writng a custom XYFuture implementation, right!?

==> With the given implementation of Future ..... couldn't we introduce a custom Runnable more lightweight?
===> Changing the implementation of ExecutionContet is for a**, if the Runnable is constructed independently ....

√iktor Ҡlang

unread,
Mar 24, 2014, 8:06:23 PM3/24/14
to scala-l...@googlegroups.com



On Tue, Mar 25, 2014 at 1:00 AM, Martin Senne <martin...@googlemail.com> wrote:
Hi Voctor,

Is that Viktor + Doctor?
 

sorry, but I have to be very picky


private[concurrent] object Future {
  class PromiseCompletingRunnable[T](body: => T) extends Runnable {
    val promise = new Promise.DefaultPromise[T]()

    override def run() = {
      promise complete {
        try Success(body) catch { case NonFatal(e) => Failure(e) }

      }
    }
  }

  def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.prepare.execute(runnable)
    runnable.promise.future
  }
}


That is the excerpt from Future.apply(...) .....

=> With the given implementation of Future.apply(..), there is no chance to exchange the Runnable by a custom Ruannable except writng a custom XYFuture implementation, right!?

You can do whatever you want:

val ec = new ExecutionContext {
  def execute(runnable: Runnable): Unit = doTheMacarena()
  …
}

val f = Future(System.exit(1))(ec)
 

==> With the given implementation of Future ..... couldn't we introduce a custom Runnable more lightweight?

More lightweight in what sense? You have full control over what gets executed, since you can create the ExecutionContext.
 
===> Changing the implementation of ExecutionContet is for a**, if the Runnable is constructed independently ....

I'm not sure I follow.

Could you show, with a piece of code, what the problem seems to be?

Martin Senne

unread,
Mar 25, 2014, 6:30:46 AM3/25/14
to scala-l...@googlegroups.com
Hi Viktor,

sorry for the misspelling(s)!
... as long as I do not call you "Captain Future" by mistake ;)
Okay, back to business.

Yesterday I was somehow really imprecise. Sorry for that.

Referring to the code,  it will hopefulle become evident what I want:


The current problem is the implementation of concurrent.Future.apply( ... )

  def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body)

It calls the impl.Future(body) which is

  def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.prepare.execute(runnable)
    runnable.promise.future
  }


There is no point for extension on the construction of the Runnable (line in red) and that is what I referred to yesterday.

Expressed differently: What can I do at the moment to have a regular concurrent.Future with a customized Runnable (instead of PromiseCompletingRunnable). The Runnable of course needs to return access to a future (e.g. via Promise.future as in PromiseCompletingRunnable or via a completely different mechanism)

Thus and IMO, the following alternatives pop up:
  • (best in my opinion, but that requires extension of the current ExecutionContext)
    • create a new method in interface ExecutionContext: def createRunnable(), that allows the creation of a custom Runnable . Or some similiar (factory) mechanism to create a Runnable
  • (ok, but not sure about the overall-consequences)
    • use a separate object ( call it CustomFuture here ), not deriving from Future, which only has an apply-method to create a Future based on a custom Runnable.
  • (worst)
    • derive from Future and override apply, such that it does not use PromiseCompletingRunnable but other Runnables instead

What do you think?


Cheers,

Martin

√iktor Ҡlang

unread,
Mar 25, 2014, 6:47:55 AM3/25/14
to scala-l...@googlegroups.com
Hi Martin,

On Tue, Mar 25, 2014 at 11:30 AM, Martin Senne <martin...@googlemail.com> wrote:
Hi Viktor,

sorry for the misspelling(s)!
... as long as I do not call you "Captain Future" by mistake ;)

lol!
 
Okay, back to business.

Yesterday I was somehow really imprecise. Sorry for that.

Referring to the code,  it will hopefulle become evident what I want:


The current problem is the implementation of concurrent.Future.apply( ... )

  def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body)

It calls the impl.Future(body) which is

  def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.prepare.execute(runnable)

Since you can control which ExecutionContext is passed in, and the ExecutionContext is passed the runnable in the execute method, you are free to do anything you want with the runnable, create a new one instead or whathaveyou.

I'm sorry, but I still do not understand what the problem is.
Is it: "The type PromiseCompletingRunnable" is not accessible to my program and therefor I do not have access to the thunk that is to be executed."?

As said before, Future.apply is far from the only way to create a Future. Why don't you just create your own Future-creation factory?

object BetterFuture {
  def apply[T](body: => T)(implicit ec: ExecutionContext): Future[T] = ec.prepare.execute(new AwesomeRunnable(body))
}

I feel like I am missing something fundamental here.
Reply all
Reply to author
Forward
0 new messages