3

I'm wondering if the following short snippet, which does show repetition can be made more DRY. I seem to be hitting these kind of constructions quite often.

Say I want some computation to be done either synchronous or asynchronous, which is chosen at runtime.

for(i <- 1 to reps) {
  Thread.sleep(expDistribution.sample().toInt)
  if (async) {
    Future {
      sqlContext.sql(query).collect()
    }
  } else {
    sqlContext.sql(query).collect()
  }
}

It feels clumsy repeating the call to the sqlContext. Is there an idiom for this trivial recurring construct?

hbogert
  • 4,198
  • 5
  • 24
  • 38

2 Answers2

6

You can "store" your computation in a local def and then evaluate it either synchronously or asynchronously

def go = sqlContext.sql(query).collect()

if(async) Future(go) else Future.successful(go)
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • This changes the semantics - wouldn't introducing a `def` be more appropriate refactor than `lazy val`? – Chris Martin Sep 02 '15 at 08:09
  • So the expression is evaluated when go is called. This seems so trivial, but C++/Java/PHP/Python do not allow for this kind of thing right? What is this functionality called in Scala? - it's hard to Google for. – hbogert Sep 02 '15 at 08:33
  • @hbogert These are called ["nested functions"](http://docs.scala-lang.org/tutorials/tour/nested-functions.html), and they're crucial to functional programming. They're often used to define auxiliary recursive functions. C++ supports [something similar](http://stackoverflow.com/a/4324829/857807), but not quite the same, using lambdas. I don't think Java 7 has anything like this, but maybe Java 8 does, I'm not sure. – dcastro Sep 02 '15 at 08:37
  • @hbogert Python also supports this. You can have a `def` inside another `def` – Kolmar Sep 02 '15 at 08:41
  • Of course. I misunderstood the Scala syntax. I thought more magic was going on as if this was leaning towards macros, but of course it's the same as: `def go () : Unit = { sqlContext.sql(query).collect() }` – hbogert Sep 02 '15 at 08:46
  • @hbogert Exactly :) All those extra symbols can be omitted here. – dcastro Sep 02 '15 at 08:48
1

You can execture Future in your current thread using MoreExecutors.directExecutor() which is implemented in guava library.

(If you don't wan't to use guava library, see this question)

Using this method, you can switch the execution context according to async flag.

Here's the sample code.

You can see that setting async flag to false makes each Future executed in order.

import com.google.common.util.concurrent.MoreExecutors
import scala.concurrent.{Future,ExecutionContext}
import java.lang.Thread
object Main {
  def main(args:Array[String]){
      val async = false // change this to switch sync/async
      implicit val ec = if(async){
        ExecutionContext.Implicits.global // use thread pool
      }else{
        ExecutionContext.fromExecutor(MoreExecutors.directExecutor) // directy execute in current thread
      }

      println(Thread.currentThread.getId)

      Future{
        Thread.sleep(1000)
        println(Thread.currentThread.getId)
      }
      Future{
        Thread.sleep(2000)
        println(Thread.currentThread.getId)
      }
      Thread.sleep(4000) // if you are doing asynchronously, you need this.
  }
}
Community
  • 1
  • 1
ymonad
  • 11,710
  • 1
  • 38
  • 49
  • I should've stated that the Future was not the main subject of the code snippet and question. Still, a welcome answer. – hbogert Sep 02 '15 at 08:21