tksfz
tksfz

Reputation: 2970

What is the Scala equivalent to Clojure's threading macros?

Clojure has the "threading macros" -> and ->>. I'm pretty sure a similar construct can be used in Scala code to replace code like:

var myObj = MyObject(x, y, z)
myObj = transform(myObj, abc)
myObj = transformMore(myObj, def)
myObj = transformYetMore(myObj, bar)

I'd love to see a worked-through example to see if it looks good. I'm pretty sure you don't need to use macros in the Scala case.

Upvotes: 9

Views: 1298

Answers (2)

nuaavee
nuaavee

Reputation: 1356

Good question! I can think of several instances where something like this can come in handy. To give an example, I am working with a dataset and I want to apply several functions on it while carrying the results forward like this:

val result: ResultSet = Functions.thread(inputSet)
                                 .andThen(execute(_, executionContext))
                                 .andThen(_.filter(_.nonEmpty))
                                 .andThen(verifyData(_, verificationHelper))
                                 .andThen(_.cache)
                                 .andThen(saveSnapshot)

To write the same without threading, you will need to either nest calls or save results of intermediate function calls. I prefer using the above method as it does the same thing in less number of lines which improves maintainability and readability of my code.

Here is the Functions utility to achieve this:

object Functions {
  def thread[T](item: T) = new ThreadFunctor(item)
}

class ThreadFunctor[T](val item: T) {
  def andThen(f: T => T): ThreadFunctor[T] = new ThreadFunctor(f(item))
}

object ThreadFunctor {
  implicit def threadToItem[T](thread: ThreadFunctor[T]): T = thread.item
}

Upvotes: 5

om-nom-nom
om-nom-nom

Reputation: 62835

Threading macros in clojure is used to solve problem of overly nested expressions, thus it is very uncommon in scala to use some kind of threading utilities (although it is possible in principle, as Stefan mentioned) because ordinary collections functions are fine

def square(x: Int) = x * x
def plusOne(x: Int) = x + 1
List(1,2,3,4).map(square).map(plusOne)

Or even lengthy ones:

someCollection.map(...)
              .flatMap(...)
              .filter(...)
              .map(...)
              ...

The other alternative is for comprehension (much more useful for options and futures). If you're not happy with this, you don't need to use macros, there are many blog posts on such constructs, for example this one

Upvotes: -1

Related Questions