-
Website
http://www.drmaciver.com -
Original page
http://www.drmaciver.com/2008/08/functional-code-not-equal-good-code/ -
Subscribe
All Comments -
Community
-
Top Commenters
-
llimllib
1 comment · 2 points
-
David R. MacIver
1 comment · 1 points
-
-
Popular Threads
I think that your point is spot on: don't marry yourself to a particular methodology just because it solves *some* problems well (or even worse, just because it's "hip"). Even Scala's standard library adheres to this principle, implementing functional constructs (like everyone's favorite persistent collection: List) using imperative algorithms for efficiency.
While I think that it is *rare* that a trivial computation such as the ones you illustrated can be cleaner imperatively than in the functional style, there do exist many examples of a non-trivial nature for which this holds. The beauty of Scala is that it doesn't restrict you to one or the other, letting you mix and match, getting the best of both worlds. I suppose that sounds like PR, but it really does solve this problem of divergent methodologies quite nicely.
I've found that if it "works" it must fit the basic definition of "good". While there is better ways to do most anything these days, good is often good enough.
I enjoyed your article, though. I think you're correct in what you're essentially saying... just because it's FP doesn't mean there's not more than one way to do it.
myCollection.sumFrom(0);
Can Scala guess an appropriate zero, based on the type of the elements of the collection, for use with .sum()?
What is "bad" in your eyes may be "good" in mine and vice versa. It usually boils down to your cognitive setup (previous experience, preferences, priorities etc.).
Certainly for trivial computations I find that the functional style works better. For non-trivial ones it's often better, but occasionally you have to vastly reorder your thinking in order to get results that are only somewhat better (or even worse) than the imperative version.
Tony:
Unfortunately, Scala's numeric hierarchy sucks profoundly, so there's not a good way to abstract between different types of numbers. Even getting sumFrom to work properly is a bit of a nuisance. In principle this is just an implementation detail though, and it should be possible to write a sum method that does the right thing based on type (It's even mostly possible to retrofit this onto the hierarchy without changing the library implementation or language, but no one has done so).
Collin, Muharem:
There's a time and a place for stating your axioms and elaborating on the meaning of a term. I didn't feel this was it.
For these purposes I'm talking mostly about code reuse and code complexity relative to the task solved.
I don't think the issues your addressing is really an imperative versus functional. It's an issue of "how small of common expression is too small to factor into another method/function?"
I think you're saying: "If the meaning of the expression is unclear and the meaning of the name will be clear, make it a named method/function."
That makes sense to me, until I end up with 20,000 methods with names longer than the expressions they contain...
RE the implementation of sum, I don't really care how the sum method is implemented to be honest. If Iterable had a reduce method (as opposed to reduceLeft and reduceRight) I might advocate sum(x : Collection[Int]) = if (x.isEmpty) 0 else x.reduce(_+_) to prevent from introducing artificial order dependencies. But that's neither here nor there.
As far as factoring into small methods go: Obviously you have to find a middle ground. There are various rules of thumb as to when to do this and when not. I'm certainly not advocating def plusOne(x : Int) = x + 1. In fact, I'm not really advocating anything at all. This post is more of a cautionary tale than an instruction set to follow.
I don't believe that your example demonstrates what you're attempting to demonstrate. Functional programing IMHO is more than replacing for loops with map/fold/recursion etc. The key benefit is referential transparency. Or avoiding *visible* side effects. Both the functional and the non-functional examples could be wrapped up in a function and both functions would be referentially transparent, and therefore would both be employing the functional programming paradigm. In fact if you were to look under the covers of the foldLeft function you may find out that it mutates some variable somewhere. Likewise if you look at the code that is generated by ghc (a haskell compiler) you'll see that some of the code it generates is also imperative. That doesn't make haskell an imperative language, because whether or not there is mutation happening under the covers is irrelevant in haskell all functions are referentially transparent and the haskell programmer can pretend that no mutation is taking place ever. It's probably possible to come up with some examples where an imperative approach is better than a functional approach, but to really show that you're going to have to use more than a single line of code. You'll have to have multiple functions, where at least one of them modifies some global, or object variable, and that causes at least one function to return different results given the same input. I think demonstration can be done, but it will take more work.
type T = { def +[A <% T](o: A): T }
def sum(nums: Iterable[T]) = nums.reduceLeft[T](_+_)
Scala doesn't support self-referencing types (classes are fine, types are not). I'm sure there's some deep theoretical reason why this is, but it does get a little annoying for situations like this one.
I wouldn't like to do it that way because the structural types implementation sucks. :-)
The way I'd like this to work is with a decent numeric hierarchy in Scala. Unfortunately we don't have one.
Side effect free code is a good practice to follow and has nothing to do with functional programming - just because it is a side effect to functional programming.
I find it irritating that the practice of side effect free code his hijacked by functional programmers and claimed to be "functional".
It's like anyone using cheese on top of something is employing the "Pizza paradigm".
Peace
-stephan
Peace
-stephan