I am a lazy programmer. I just start to get comfortable with C# (or VB if that's your favorite) and object-oriented (OO) stuff: encapsulation,
inheritance, polymorphism, etc. Here comes the new buzz words, F# or functional programming (FP). Do I have to start from scratch to learn a new
language all over again? Will I be irrelevant in 2 or 3 years if I am not catching up? Exactly what is the fuzz about FP?
hours of googling and visiting dozens of FP introduction websites, I was still in the dark. Some of the websites threw out tons of computer
science jargons intended for those who already knew what FP is all about. The others quickly jumped into "Hello World" examples, introducing the
syntax, not the concept, to those who have already decided to learn the new language. As a lazy programmer currently comfortable and productive
with OO stuff, I am not sold on FP just yet. I am glad I have not wasted much time on the dynamic language frantic, such as Iron Ruby or Iron Python, which is short-
lived. Will FP be a different story? I need something to convince me that FP is a true game changer, not another pretender. Especially, I
would like to see a simple yet practical example that demonstrates the TRUE, not syntactic, difference between FP and OO
The killer example
Here is a simple class with several properties.
The task is to write an overloaded method to load an instance from various data sources, such as
DataTable filled by
DataReader resulted from
DbCommand.ExcuteReader(), or property/value pairs read from
configuration files. Below are the signatures of the method overloads.
Piece of cake. Here we go.
Wait a minute. Something is fishy here. The method bodies are exactly the same! That's a violation of the DRY (Don't Repeat
Yourself) or DIE (Duplication is Evil) principle. Duplicated code is a maintenance headache. If, for example, a new property was added to the
class, all three overloaded methods would have to be modified. The code should be refactored so that such requirement changes result in code
changes in only one place. Upon closer examination, however, it turns out there is no straightforward OO way to refactor the code, because the
three versions of
dataSrc parameter do not share a common superclass or interface that implements the string-keyed indexer
([string]). Work-around is possible. For example, use a wrapper class to force them using the same indexer.
The wrapper removes duplicated code from
LoadInstance methods. However, it is anything but pretty. It doubles lines of
code. This is like a Chinese proverb saying, "pick up a sesame seed but lose sight of a watermelon" (focus on details but miss the big picture).
The big picture here is to reduce maintenance cost by avoiding code duplication. Increasing code size adds more code to maintain, defeating the
big picture in the first place. In fact, it does not eliminate the duplication. It just moves the duplication from
methods to the wrapper class. In some cases, the wrapper may actually introduce more code changes. For example, in order to load instances from a
new type of data source, the original version needs only another overload, while the wrapper version needs additional code to wrap the new data
Another work-around, which avoids code duplication without increasing code size, is to use Reflection to invoke the indexer from the
common super class (
object), as shown below.
Boy is it uglier! Albeit shorter, the code is much harder to read. Hard-to-read code is also difficult for maintenance. More
importantly, it is magnitude slower. This is like another Chinese proverb saying, "cut the feet to fit the shoes." You put on shoes in order to
protect your feet. But your action actually does more harm than good.
So what has FP to offer?
I call this elegancy.
Yes, FP is available in your favorite language, C# or VB. It is not specific to F#, so you don't have to start from scratch.
In fact, you can do FP even in .Net 2.0 using delegates. Since .Net 3.5, FP becomes "native" after a new generic delegate (Func) is predefined,
and a new syntax (lambda expression) for anonymous
delegates is introduced.
What makes the killer
The example is carefully selected, so that the refactored
LoadInstance method does not care the actual object of
dataSrc. It only needs to know the behavior, or function, by which the
dataSrc returns an object given a string-valued
key. In OO paradigm, however, you cannot pass a "pure" function to a method. All functions are attached to objects. There are no stand-alone pure
functions. Although you can define behaviors using function-only interfaces and pass them as parameters, they are objects’ behaviors, not
pure behaviors. You cannot instantiate or pass a pure interface. Any interface is eventually implemented through a concrete object. In this
example, the need for a pure function as method parameter makes both OO implementations looking awkward.
In FP paradigm, functions become
first-class citizens as objects. In addition to their traditional roles as pieces of reusable code defined at design time, functions can now be
constructed and manipulated at runtime. They can also be passed around as parameters. In other words, functions are abstracted to the same level
as objects. While objects enable you to encapsulate entities with internal states and behaviors, functions give you the ability to model pure
behaviors not attached any particular entities. More precisely, model behaviors of generic objects, or generic behaviors. In this case, FP enables
us to model the generic behavior of a string indexer (
getVal) in the
load method; and lambda expression enables us to
single out and pass just the string indexers from different types of
dataSrc. This gives the elegancy to the FP
The ability to model behaviors is a true game changer, not a syntactic sugar. Just look what changes LINQ has brought along.
LINQ completely changes the way you think about data manipulation. Before LINQ, you code how to manipulate data. With LINQ, you code what data you
need. It is not an accident that most LINQ keywords are not nouns, such as
distinct, etc. It is only because they are modeling behaviors, not entities.
Next time when you are given a requirement statement to architect a new project, in addition to nouns, you could also circle those recurring
verbs, adverbs, or even conjunctions. FP enables you to model generic behaviors and bring your project to the next level.
Please login to rate or to leave a comment.