Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: custom control structures with several code blocks

Is it possible to create a custom control structure with several code blocks, in the fashion of before { block1 } then { block2 } finally { block3 }? The question is about the sugar part only - I know the functionality can be easily achieved by passing the three blocks to a method, like doInSequence(block1, block2, block3).

A real life example. For my testing utilities I'd like to create a structure like this:

getTime(1000) {
  // Stuff I want to repeat 1000 times.
} after { (n, t) => 
  println("Average time: " + t / n)
}

EDIT:

Finally I came up with this solution:

object MyTimer {
  def getTime(count: Int)(action : => Unit): MyTimer = {
    val start = System.currentTimeMillis()
    for(i <- 1 to count) { action }
    val time = System.currentTimeMillis() - start
    new MyTimer(count, time)
  }
}

class MyTimer(val count: Int, val time: Long) {
  def after(action: (Int, Long) => Unit) = {
    action(count, time)
  }
}

// Test
import MyTimer._

var i = 1
getTime(100) {
  println(i)
  i += 1
  Thread.sleep(10)
} after { (n, t) => 
  println("Average time: " + t.toDouble / n)
}

The output is:

1
2
3
...
99
100
Average time: 10.23

It is mostly based on the answer by Thomas Lockney, I just added the companion object to be able to import MyTimer._

Thank you all, guys.

like image 603
Vilius Normantas Avatar asked Jan 01 '11 08:01

Vilius Normantas


2 Answers

General principle. You can of course have f take parameters as well. (Note that the name of the methods have no meaning in this example.)

scala> class Foo {
     | def before(f: => Unit) = { f; this }
     | def then(f: => Unit) = { f; this }
     | def after(f: => Unit) = { f; this }
     | }
defined class Foo

scala> object Foo { def apply() = new Foo }
defined module Foo

scala> Foo() before { println("before...") } then {
     | println("then...") } after {
     | println("after...") }
before...
then...
after...
res12: Foo = Foo@1f16e6e
like image 109
Knut Arne Vedaa Avatar answered Sep 25 '22 22:09

Knut Arne Vedaa


If you want these blocks to appear in the specific order, this change to Knut Arne Vedaa's answer would work:

class Foo1 {
  def before(f: => Unit) = { f; new Foo2 }
}

class Foo2 {
  def then(f: => Unit) = { f; new Foo3 }
}

...
like image 37
Alexey Romanov Avatar answered Sep 22 '22 22:09

Alexey Romanov