A few days ago David Pollak did a blog showing the differences between a simple function to parse a string and return a number written in Scala in an "imperitive style" and in a "functional style." I commend the post and think many more like it are needed. It is very difficult for a person accustomed to imperitive programming to think in a functional way, and without simple examples comparing the code for common programming tasks, I think most programmers loose patience with functional programming.
That all being said, I don't like David's example functional function:
- I think the conversion of the string to a list obfuscates what the function is doing, not to mention consumes resources unnecessarily.
- I find his use of pattern matching confusing, especially the way list operations are mixed in with it. I spent more time than I willing to admit trying to make sense of it.
- His nested function, p, has too many parameters.
So, being that criticism of code without code in return tends to be rather pointless, here's my attempt at the function. I obviously like it better, but I'm neither as familiar with functional programming nor as familiar with Scala as David is.
object Parsely {
def erikParseNumber(in: String): (Long, Int) = {
if (in eq null) (0L, 0)
else {
val tin = in.trim()
if (tin.length == 0) (0L, 0)
else {
val sign = if (tin.charAt(0) == '-') -1L else 1L
def p(cur: Long, pos: Int): (Long, Int) = {
if (pos == tin.length || !tin.charAt(pos).isDigit) (cur * sign, pos)
else p((cur * 10L) + tin.charAt(pos).toLong - '0'.toLong, pos + 1)
}
p(0L, if (tin.charAt(0) == '-' || tin.charAt(0) == '+') 1 else 0)
}
}
}
}
So I've done the following:
- I'm using the "pos" parameter as an index into the string, instead of making a list.
- In the nested function, I'm accessing some of the values from the enclosing scope instead of passing them as parameters. This reduces the number of parameters from 4 to 2.
- I'm using if/else expressions instead of pattern matching
So what do you think? I find my version more readable, and I think it is a little more efficient. However, I haven't tested it much, so maybe there's a bug. If so, please point it out and I'll fix it.