17

How can I refactor this code in functional style (scala idiomatic)

def findFirst[T](objects: List[T]):T = {
  for (obj <- objects) {
    if (expensiveFunc(obj) != null) return obj
  }
  null.asInstanceOf[T]
}
snappy
  • 2,761
  • 5
  • 23
  • 24

3 Answers3

22

This is almost exactly what the find method does, except that it returns an Option. So if you want this exact behavior, you can add a call to Option.orNull, like this:

objects.find(expensiveFunc).orNull
sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 5
    No need to mention that the use of `Option` is much more idiomatic than using `null`… And much safer. – Jean-Philippe Pellet Jul 18 '11 at 07:39
  • 3
    For the curious, here's the library source of `TraversableLike.find`: https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_0_1/src//library/scala/collection/TraversableLike.scala#L330 – kassens Jul 18 '11 at 16:22
6

First, don't use null in Scala (except when interacting with Java code) but Options. Second, replace loops with recursion. Third, have a look at the rich API of Scala functions, the method you are looking for already exists as pointed by sepp2k.

For learning puprose your example could be rewritten as:

def findFirst[T](objects: List[T]):Option[T] = objects match {
    case first :: rest if expensiveFunc( first ) != null => Some( first )
    case _ :: rest => findFirst( rest )
    case Nil  => None
}
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
0

How about a fold?

Our somehow pseudo-expensive function:

scala> def divByFive (n: Int) : Option[Int] = {
     | println ("processing " + n)               
     | if (n % 5 == 0) Some (n) else None } 
divByFive: (n: Int)Option[Int]   

Folding on an Option:

scala> ((None: Option[Int]) /: (1 to 11)) ((a, b) => 
     |   if (a != None) a else divByFive (b)) 
processing 1
processing 2
processing 3
processing 4
processing 5
res69: Option[Int] = Some(5)
user unknown
  • 35,537
  • 11
  • 75
  • 121