Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the accepted/recommended syntax for Scala code with lots of method-chaining?

Tags:

In Scala I tend to favour writing large chained expressions over many smaller expressions with val assignments. At my company we've sort of evolved a style for this type of code. Here's a totally contrived example (idea is to show an expression with lots of chained calls):

import scala.util.Random val table = (1 to 10) map { (Random.nextInt(100), _) } toMap  def foo: List[Int] =   (1 to 100)     .view     .map { _ + 3 }     .filter { _ > 10 }     .flatMap { table.get }     .take(3)     .toList 

Daniel Spiewak's Scala Style Guide (pdf), which I generally like, suggests the leading dot notation in the chained method calls may be bad (see doc: Method Invocation / Higher-Order Functions), though it doesn't cover multi-line expressions like this directly.

Is there another, more accepted/idiomatic way to write the function foo above?

UPDATE: 28-Jun-2011

Lots of great answers and discussion below. There doesn't appear to be a 100% "you must do it this way" answer, so I'm going to accept the most popular answer by votes, which is currently the for comprehension approach. Personally, I think I'm going to stick with the leading-dot notation for now and accept the risks that come with it.

like image 455
overthink Avatar asked Jun 24 '11 18:06

overthink


1 Answers

The example is slightly unrealistic, but for complex expressions, it's often far cleaner to use a comprehension:

def foo = {   val results = for {     x <- (1 to 100).view     y = x + 3 if y > 10     z <- table get y   } yield z   (results take 3).toList } 

The other advantage here is that you can name intermediate stages of the computation, and make it more self-documenting.

If brevity is your goal though, this can easily be made into a one-liner (the point-free style helps here):

def foo = (1 to 100).view.map{3+}.filter{10<}.flatMap{table.get}.take(3).toList //or def foo = ((1 to 100).view map {3+} filter {10<} flatMap {table.get} take 3).toList 

and, as always, optimise your algorithm where possible:

def foo = ((1 to 100).view map {3+} filter {10<} flatMap {table.get} take 3).toList def foo = ((4 to 103).view filter {10<} flatMap {table.get} take 3).toList def foo = ((11 to 103).view flatMap {table.get} take 3).toList 
like image 80
Kevin Wright Avatar answered Sep 22 '22 13:09

Kevin Wright