With the rise of Scala and Clojure, there’s been a lot of talk lately about procedural vs. functional styles of coding. Most developers are accustomed to procedural coding, and functional can be hard to get a handle on. I was working through Programming in Scala (again) this morning, and I came upon this function:
// Procedural implementation def longestWord(words: Array[String]) = { var word = words(0) var idx = 0 for (i <- 1 until words.length) if (words(i).length > word.length) { word = words(i) idx = i } (word, idx) }
The purpose of this function is to find the longest word in the passed-in array, and return a tuple with that longest word, and its index in the array. You can see that in this function, we have two vars, one for the current longest word, and another for its index in the array. We then use a for expression to walk the array, reassigning word and idx when we find a longer word. This is very much like how you would write this in Java.
I decided to rewrite this function in a more functional style, just to see how my functional chops are coming along. Here’s what I ended up with:
// A more functional implementation def longestWord(words: Array[String]) = (("", -1) /: words.zipWithIndex) {(old, cur) => if (cur._1.length > old._1.length) cur else old }
First of all, notice how much shorter this function is than the first one. Also, notice that there is only a single expression in the function, so the outer curly braces aren’t necessary. What this expression is doing is calling zipWithIndex on the passed-in array, which results in an array of tuples containing each word and its index. We then call foldLeft using its operator name of /:, with its initial argument being a tuple with an empty string and -1 for an index. What foldLeft does is apply the function value passed to it to pairs of arguments. On the first pass, the arguments are what was passed in and the first element in the array. On the second iteration, the arguments are the result of the first pass and the second element in the array. This then continues through the entire array. What is returned after the final pass will be a tuple that contains the longest word in the array, and its index.
Now, I don’t claim to be a functional master or anything, but I think this is a decent illustration of how the functional style can reduce the lines of code, and the number of mutable variables, while making the code easier to read and understand.
The second function is also much harder to read. I’ll take a method that’s 40 characters more verbose but more readable over this new version any day.
Interesting. I find the 2nd one extremely easy to read.
Of course, since you wrote it 🙂
Read this again in six months…
The readable of each really depends a lot on the amount of time spent with a particular grammar. Once you really start using Scala more and more, the readability becomes easy. There’s a big difference in traditional OOP vs. truly functional programming. Mutability, stateful vs stateless, etc
Java as a language has been dying because it lacks higher level abstractions.
Regards,
Richard L. Burton III
Java has been dying? I’m not sure this word means what you think it means…
Pingback: 99 Scala Problems #28 – I Like My Solution Better | Joey Gibson's Blog
I appreciate the article, because I learn Scala.
I too find the first version more readable… That’s the second form that makes Scala a bad reputation among Java coders, which see it as line noise.
That said, I learned just enough Scala to understand your code… once you explained it! And indeed, it is quite elegant.
But I prefer the more explicit foldLeft name to the symbol, and I find that using it in left to right reading order ease the understanding.
def longestWord(words: Array[String]) =
(words.zipWithIndex foldLeft (“”, -1))
{ (old, cur) => if (cur._1.length > old._1.length) cur else old }
Probably a matter of taste here.