Sunday, January 18, 2009

Comparing Functional to Imperative, Part 2: Economies of Syntax

This is part 2 of a series (consisting of at least two posts) comparing imperative programming languages with functional programming languages. Here is Part 1: Context determines meaning. By the way, Haskell is my prototypical functional language because it’s the purest functional language about which I know anything. C# is my prototypical imperative language because I know it pretty well.

It seems that functional algorithms and programs are quite a bit shorter than their imperative counterparts. For example, here is a possible definition of a function to calculate square values in Haskell:

	square x = x * x

For sake of comparison, here an equivalent function defined in C#:

	static double Square (double x) { return (x * x); }

The Haskell version is less than a third as long as the C# version. As far as I’m concerned, this is a win for Haskell. I much prefer a syntax that does not get in the way of what a program actually does. This is mostly why I gravitated to C# even after several years of nothing but VB. VB syntax may be easier to learn for the beginner, but I find it slows me down because I have to read (or worse write) past a bunch of words before I get to the meaningful part. Of course, C# may be concise compared to VB, but it’s hard to imagine a more concise syntax than is afforded by Haskell.

How can a functional language like Haskell get by with such an economy of syntax? One reason is that Haskell was designed to create functions, first and foremost. Do one thing and do it well, as the saying goes. Another reason is that Haskell is very good about inferring the types of things from other things. You can give things an explicit type in Haskell, but often the only reason to do so is to help the compiler help you when you screw up. For example, Haskell knows that ‘square’ is a function that returns a numeric value. It knows this because it knows that the ‘*’ operator returns a numeric value. It also knows that parameter ‘x’ must be a numeric value, likewise from the definition of ‘*’. In other words, Haskell will not let you do something like this:

	y = square "foo"

Of course, it is possible to define a function in Haskell that does not, in its definition, imply a particular return type at all. In such a case, Haskell will define the function in a generic fashion. Think C# generics without all the syntactic fluff. Consider Haskell’s ‘foldl’ (fold left) function:

	foldl f z [] = z
	foldl f z (x:xs) = foldl f (f z x) xs

Basically, ‘foldl’ applies an operation to each item in a list, accumulating the result of the operation along the way. The accumulated value is the return value of ‘foldl’. As of version 3.5, the .NET Frameworks has a function that serves the same purpose: Enumerable.Aggregate. What does it look like? Hang on to your hat…

	public static TAccumulate Aggregate(
		this IEnumerable source,
		TAccumulate seed,
		Func func)
	{
		if (source == null)
		{
			throw Error.ArgumentNull("source");
		}
		if (func == null)
		{
			throw Error.ArgumentNull("func");
		}
		TAccumulate local = seed;
		foreach (TSource local2 in source)
		{
			local = func(local, local2);
		}
		return local;
	}

Why is Haskell’s version so much shorter? One obvious answer is Haskell’s penchant for exceedingly short parameter names (something I don’t care for, actually). It’s much more than that, though. In Haskell’s version, there are no explicit types, no explicit generic parameters, and much less ‘punctuation’. Does this mean that Haskell is weakly-typed? Not at all. Haskell’s version is at least as strongly-typed as the .NET version. In fact, considering that Haskell will not let you pass invalid parameters to ‘foldl’, it can be considered to be more strongly typed than the .NET function, and also eliminates the need for parameter validation in the body of the function.

I’m not sure what part 3 of the series will be (or even if there will be a part 3), but I’m considering a post about why IO is a challenge for pure functional languages and how Monads make it much better.

Comparing Functional and Imperative, Part 1: Context determines meaning

Over the past year, I’ve taken a strong interest in functional programming. I’m not sure where it started, but it may have been Brian Beckman’s Don’t fear the Monads on Channel 9. It went pretty much completely over my head, but my interest was definitely piqued. It has been in my mind to do a series of posts on functional programming once I became an expert on the subject. Well, I am so not an expert at this point, but I’ve decided to consider that an advantage. Once something makes perfect sense to you, it’s often hard to remember why it didn’t make perfect sense before.

Functional programming is an alternate universe of programming where hard things (e.g. concurrency) become easier and easy things (e.g. writing to a file) become at least a bit harder. Besides the fact that functional programming is just plain different from imperative programming, another challenge for an imperative programmer learning functional programming is the fact that the same or similar syntax is used to represent quite different things. Consider:

	a = 3
	b = a + 2

In an imperative language context, this would probably mean “assign the value 3 to variable ‘a’, then evaluate a + 2 and assign the resulting value to variable ‘b’”. In a functional programming language such as Haskell, ‘a’ and ‘b’ can be thought of as being functions. This may not technically be true, particularly in the case of ‘a’, but I think it works to think of them that way. Just to drive the point home, here is an equivalent definition in C#:

	int a() { return 3; }
	int b() { return a() + 2; }

One concept of functional programming that is quite different from imperative programming is the idea that once you define ‘a’, you can’t change it. Of course, if ‘a’ is actually a function, then this is to be expected. Even in imperative programming languages, the definitions of functions generally don’t change in a compiled program. The fact that ‘a’ is a function also explains something else that is at first peculiar about functional programming, which is the order in which statements get evaluated. Consider:

	a = 3
	b = a + 2
	c = b + 1

In an imperative program, the first line would be evaluated first, followed by the second line and so on. But what if ‘a’, ‘b’ and ‘c’ are actually functions? The equivalent C# code might look something like this:

	int a() { return 3; }
	int b() { return a() + 2; }
	int c() { return b() + 1; }

If there were some code that referenced the ‘c’ function, program execution would jump to function ‘c’, then to function ‘c’ and so on. Furthermore, if no other code in the program referenced functions ‘b’ or ‘c’, then neither of those functions would ever execute. So it is in functional programming. The point is that if we think of syntax like “foo = ...” as defining a function, it’s easier to grasp as opposed to thinking of it as a statement with special rules.

When I learned that pure functional programming has no mutable variables and no “side-effects”, my first thought was “How can I actually do anything?”. Well, Haskell (a pure functional language if there ever was one) does have side-effects, depending on how you choose to define them. For example, there are functions that perform IO (reading and writing to file streams). On the other hand, these side-effects are definitely not incidental, as they are in imperative languages. In Haskell, you know when a function may have side-effects. Generally, Haskell treats side-effecting code rather like nuclear waste, encapsulating it in a special container called a “Monad” and posting lots of scary warning signs around it.

Can a pure functional programming language be useful without side-effects? I think the answer is yes. I work for a company that creates LOBs (Line of Business apps) first and foremost. When you take all the layered architecture and technology concepts out of the picture, an LOB looks something like this:

image

That yellow arrow in the middle of the diagram is a transformation. It transforms the shape of the data as it comes from the user interface into the shape it has in the database. You could imagine that it’s a pipeline, of sorts, constructed of all manner of logical loops and branches. There is no reason that yellow arrow needs to have any mutable state within itself. In fact, for reasons of scalability and consistency, it would be better if that yellow arrow didn’t have any mutable state inside it. As such functional programs are uniquely suited to constructing this sort of pipeline.

Continue to Part 2: Economies of Syntax.

Thursday, January 1, 2009

A Confession: I don’t have a degree

I ran into a blogo-sphere discussion recently about the merits of having a CS degree. I found this particularly interesting because, well, I don’t have a degree. Shocking, I know, coming from someone who claims to be a “Software Architect” (well, that is my job title). I’ll give you a minute to recover.

To be very cathartically honest, I wish it were not true. I have a full-time+ job and a full-time+ family, but if I had an opportunity to pursue a degree, I’d seriously consider it. So there you have it. There is at least one non-degree-possessing person in this world who thinks having a degree is a good thing.

On the other hand, a lot of what I read about the purported merits of having a degree is…just crap, in my opinion. I believe and accept the fact that a lot of people have learned a lot of things in a college or university setting, things that they would never learn in “real” life. I believe and accept the fact that for most people, there isn’t a better way to get a well-rounded education. I do not believe those things are true for me.

It has been well established that there are at least a few different ways that people learn best. I think it is also reasonable to conclude that what any person has learned or been exposed to in his or her life is going to be unique to that person. For these and other reasons, concept “A” might really “click” with Alice, while Bob just doesn’t get it. For concept “B”, it may be just the opposite. In a classroom setting, the extra time it takes to teach concept “A” to Bob is a waste of time for Alice. The extra time it takes to teach concept “B” to Alice is a waste of time for Bob. This leads me to conclude that classroom learning is not particularly time-efficient.

I think the primary benefit of learning in a college/university classroom setting is the fact that most people do not have the motivation or, in some cases, the ability to educate themselves.

I love to learn. It might be more correct to say that I’m addicted to information…of any sort, really. Truly, I’m not sure I’ve ever encountered any subject matter or concept that didn’t interest me, at least a little bit. People have told me that they are intimidated to have a conversation with a subject matter expert concerning said subject matter. They’re afraid of asking an ignorant question. I can’t relate to that. I’ll happily make a fool of myself, asking that person a thousand stupid questions, just for the chance to learn something.

One idea I often encounter is the idea that a self-educated person is going to have a “narrow” education. Maybe they can become competent in their field, but they’ll be weak in other areas, which might hamper their overall performance. I think this idea “rings true” with a lot of folks. It seems logical and fair-minded. On the other hand, I’ve never encountered “hard numbers” to support this idea.

Of course, I can’t give you any hard numbers, either. In fact I can only offer one data-point: myself. If I were to be given a general knowledge test covering various aspects of Math, Science, History, English, etc., I feel confident that my score would compare very favorably with scores obtained by administering the same test to a random selection of college educated people.

Having said all that, why do I wish I had gotten a degree when I had the chance? Two reasons: First, I did attend college for three semesters. It did not go well. I spent too much time in the computer lab when I should have been in the classroom or completing assignments. Basically, I feel that I failed at college and that bothers me. Second, “Perception Is Reality”. The vast majority of people I work with and, I would guess, the vast majority of people in my field have a degree. I would venture that the majority of these people “perceive” that having a degree is better than not having one (the example set by Bill Gates notwithstanding).

I know of at least one case where I was not even considered for a position on the basis of not having a degree. I doubt that was an isolated case. If you’re dealing with an overwhelming glut of resumes, you may very well decide to trash all the resumes that don’t appear to “measure up” in all respects.

This reminds me of the recent experience I had doing the initial interview of several candidates for a Software Developer position in my division. This was a first for me, and the experience was…fascinating. I am thinking of one candidate in particular. This person came with all the right credentials. Not only did this person know everything, but this person had been working for several years at a “big name” company, and before that another “big name” company (we verified this person’s employment history). This person had an MBA.

On that basis, I was shocked, truly, at what this person did not know about Software Development. The point in the interview that I began to understand the situation was when I asked “It says on your resume that you have experience with technology ‘X’. Can you tell me more about how you used that technology?” This person’s answer was something along the lines of “Well, I didn’t use technology ‘X’ directly. My job was to review and approve other people’s work and send it up the chain.” Imagine several more responses along the same lines. Finally I asked this person to demonstrate how to solve a particular (fairly simple) problem using the language of their choice. Imagine a blank stare. I found myself describing the problem in simpler and simpler terms. The blank stare remained. I eventually realized that this person could not tell me what a “string” was. Yikes!