reactive icon indicating copy to clipboard operation
reactive copied to clipboard

add withRunner method to EventStream to switch event flow context

Open Yarikx opened this issue 11 years ago • 9 comments

it could be used to execute events on thread pools, actors, etc.

For example can be used to switch running context to UI thread in android

Yarikx avatar Jun 06 '13 12:06 Yarikx

Perhaps we should use scala.concurrent.ExecutionContext?

nafg avatar Jun 28 '13 09:06 nafg

Maybe the Runner type should simply be replaced by something like Runnable => Unit. That would simplify the type signature so that it doesn't need to be an inner type. It would also fit pretty well with the signature of many existing constructs like ThreadPool and ExecutionContext

events.withRunner{ ExecutionContext.global execute _ }

dylemma avatar Jul 10 '13 20:07 dylemma

Maybe we just need an async method that takes an implicit ExecutionContext. Anyone know how prepare is meant to be used?

On Wed, Jul 10, 2013 at 4:29 PM, Dylan Halperin [email protected]:

Maybe the Runner type should simply be replaced by something like Runnable => Unit. That would simplify the type signature so that it doesn't need to be an inner type. It would also fit pretty well with the signature of many existing constructs like ThreadPool and ExecutionContext

events.withRunner{ ExecutionContext.global execute _ }

— Reply to this email directly or view it on GitHubhttps://github.com/nafg/reactive/pull/74#issuecomment-20770744 .

nafg avatar Jul 11 '13 06:07 nafg

In that case wouldn't async be essentially the same as the current nonblocking method?

The value I see in using withRunner(runner: Runnable=>Unit) is that it could fit into non-scala things as well. For example, Java's SWT Display class has void asyncExec(Runnable runnable) and void syncExec(Runnable runnable) which cause a task to be run on the UI thread, which is sometimes mandatory. I imagine @Yarikx has similar motivations w.r.t. Android.

dylemma avatar Jul 11 '13 11:07 dylemma

How about this:

def nonblocking(implicit ec: ExecutionContext): EventStream[T]
def withRunner(runner: Runnable => Unit): EventStream[T]

dylemma avatar Jul 15 '13 16:07 dylemma

@dylemma see my comment on the google group.

Here's the interface of ExecutionContext (docs removed):

trait ExecutionContext {
  def execute(runnable: Runnable): Unit
  def reportFailure(t: Throwable): Unit
  def prepare(): ExecutionContext = this
}

If you change execute to apply (and make ExecutionContext extend Function1), essentially ExecutionContext is a Runnable => Unit, with some extra methods (one mandatory). We could even make a converter: implicit def fromFunc(f: Runnable=>Unit) = new ExecutionContext { def execute(r: Runnable) = f(r) def reportFailure(t: Throwable) = t.dumpStack // etc. }

So you can easily write an ExecutionContext for SWT a/syncExec, or the AWT event thread, or anything.

nafg avatar Jul 18 '13 08:07 nafg

Fair enough. Bonus points if that implicit doesn't need to be explicitly imported. I'm not sure, but maybe if it's defined in EventStream it may work without an import...

dylemma avatar Jul 18 '13 11:07 dylemma

On the other hand, if you're writing a function literal, in order to trigger an implicit conversion you have to write the types explicitly, but if you call the conversion explicitly the types can be inferred. So it's not really buying anything.

1a. implicit val nowRunner: ExecutionContext = {r: Runnable => r.run() }; val es2 = es.async 1b. val es2 = es.async((: Runnable).run()) 2a. implicit val nowRunner = fromFunc(.run()); val es2 = es.async 2b. val es2 = es.async(fromFunc{r => r.run() })

nafg avatar Jul 21 '13 11:07 nafg

I'm thinking to address this by using an ADT isomorphic to how RxJava handles success, failure, and END with separate execution paths. Basically foreach(A => Unit) is short for something like observe(Event[A] => Unit) where type Event = Success[A] | Failure | End.

nafg avatar Sep 07 '14 18:09 nafg