Critical Development

Language design, framework development, UI design, robotics and more.

Functional Programming as Intensity of Expression

Posted by Dan Vanderboom on September 20, 2008

On my long drive home last night, I was thinking about the .NET Rocks episode with Ted Neward and Amanda Laucher on F# and functional programming.  Though they’re writing a book on F# together, it seems even they have a hard time clearly articulating what functional programming is all about, and where it’s all headed in terms of mainstream commercial use… aside from scientific and data transformation algorithms, that is (as with the canonical logging example when people explain AOP).

I think the basic error is in thinking that Functional is a Style of programming.  Yet, to say that so-called Imperative-based languages are non-functional is ridiculous.  Not in the sense that they “don’t work”, but that they’re based on Objects “instead of” Functions.

This isn’t much different from the chicken-and-egg problem.  Though the chicken-and-egg conundrum has a simple (but unobvious) answer, it doesn’t really matter whether the root of program logic is a type or a function.  If I write a C# program with a Program class, the Main static function gets called.  Some action is the beginning of a program, so one might argue that functions should be the root-most logical construct.  However, you’d then have to deal with functions containing types as well as types containing functions, and as types can get very large (especially with deep inheritance relationships), you’d have to account for functions being huge, spanning multiple code files, and so on.  There’s also the issue of types being organizational containers for functions (and other members).  Just as we use namespaces to organize our types, so we use types to organize functions.  This doesn’t prevent us from starting execution with a function or thinking of the program’s purpose functionally; it just means that we organize it inside a logical container that we think of as a “thing”.

Does this limit us from thinking of business processes as functional units?  Ted Neward suggests that we’ve been trained to look for the objects in a system, and base our whole design process on that. But this isn’t our only option for how to think about design, even in our so-called imperative languages.  If we’re thinking about it wrong, we can and should change the process; we don’t need to blame our design deficiencies on the trivial fact of which programming construct is the root one.  In fact, there’s no reason we should use any one design principle to the exclusion of others.  Looking for the things in the system is and will remain a valuable approach for discovering and defining database schemas and object models.  The very fact that “functional languages” aren’t perceived as especially useful for stateful components isn’t a fault of a style of programming, but is rather a natural consequence of functions being an incomplete aspect of a general purpose programming language.  Functional is a subset of expressive capability.

Where “functional languages” have demonstrated real value is not in considering functions as root-level constructs (this may ultimately be a mistake), but rather in increasing the flexibility of a language to be much more expressive when defining functions.  Making functions first-class citizens that can be passed as parameters, returned as function values, and stitched together with metaprogramming techniques, is a huge step in the right direction.  The use of simple constructs such as operators to match patterns, reverse the evaluation of functions and the flow of values with piping, and perform complex set- and list-based operations, all increase the expressive intensity and density of the functions in a language.  This can only add to the richness of our existing object models.

Sticking objects together in extensible and arbitrarily complex structures is routine for us, but now we’re seeing a trend toward the same kind of composability in functions.  Of course, even this isn’t new, per se; the environmental forces that demand this power just haven’t become significant enough to require that level of power in mainstream languages, because technology evolution (like evolution in general) tends to work by adapting solutions that are “good enough”.

It’s common to hear how F# is successfully incorporating “both functional and imperative” styles into one language, and this is important because what we need is not so much the transition to a functional style, as I’ve mentioned already, but a growth of greater functional expressiveness and power in existing, successful, object-oriented languages.

So let our best and favorite languages grow, and add greater expressive powers to them, not only for defining functions, but also in declaring data structures, compile-time constraints and guarantees, and anything else that will help to raise the level of abstraction and therefore the productivity with which we can naturally express and fulfill our business needs.

Ultimately, “functional programming” is not a revolutionary idea, but rather an evolutionary step forward.  Even though it’s impact is great, there’s no need to start from scratch, to throw out our old models.  Incompatibility between functional and imperative is an illusion perpetuated by an unclear understanding of their relationship and each aspect’s purpose.

4 Responses to “Functional Programming as Intensity of Expression”

  1. I can mostly see where you are coming from and although I do disagree with parts, I can agree with the fact that they are both ways of expressing solutions to complex problems and can be used in combination to better the solutions. It really is all about the business problem and finding the best suited solution for them regardless of the language. I’d like to quickly lay out a few of my thoughts.

    I like seeing the trend toward FP in our current languages, when it is appropriate. Sometimes however, we are using FP as the new posh thing, and not recognizing that it can add overhead when used incorrectly. Obviously never use any tool/pattern/idea just to say you used it!

    A programming paradigm is a set of guidelines, not a strict set a rules that cannot be broken. There is a mindset shift when going from OO to FP, or vice versa. It’s not really about objects instead of functions, as much about where we are placing focus. The constructs that you use to express different elements of a program are different. The ideas are different. Just because a language has the constructs available, does not make it well suited to the paradigm. I think what Ted meant is that we are taught to think in a certain way when we are confronted with a problem. FP gives us another way to think about it.

    Don’t you feel as though the amount of “ceremony” existing in our current OO languages makes it hard to express things in an elegant succinct way? I like F# for not only the functional constructs, but the syntax itself is a major step forward in my mind! I’m not asking anyone to stop using their favorite OO language in favor of F# or Scala, I’m simply stating that I see great value for these newer fusion languages.

    To clarify for your readers, functional programming is by no means new. In fact it is quite old. Lambda calculus formalism was created at the same time Alan Turing was busy with the Turing Machine. These ideas have been greatly separated with the US military adopting Turing’s ideas, and academia adopting Church’s Lambda Calculus. The ideas have been merged in other languages, but this is the first time that we are able to see them together on platforms with such widespread use (JVM & CLR).

    I have enjoyed your blog and hearing your point of view.

  2. Ha! Yeah, that formatting happens when you do something too quickly. Sorry.

  3. Dan Vanderboom said

    Hi Amanda,

    A programming paradigm may not impose a strict set of rules, but specific compilers designed around that paradigm certainly do impose artificial restrictions (to protect programmers from themselves, in most cases). Why do you think VB or C# would turn down the use of some of the constructs that we get so excited about in F# and other functional languages? It’s a set of social decisions, a language conservatism, a concern about confusion and abuse of power. I think that because each of these features could be equally ignored, used appropriately, or abused, the use of one language feature doesn’t preclude the sensibility of the others. However, the question is always: “is this community of developers ready for this?” In a new language like F#, it’s easy to break with tradition, because basically there is none.

    I don’t feel that our OO languages encourage or demand “ceremony” for the sake of ritual itself. Instead, I feel that the lack of expressive capability is what forces us to make much greater efforts to accomplish the same goal, when a language like F# might be able to do it much more succinctly. If I have an operator that performs a common set-based operation, or some pattern matching primitives, this is going to contribute to the fluidity of my function definitions, instead of having to declare several types (and their relationships, and their initialization and use) to accomplish the same basic coordination or transformation goal. We do this because there’s no other way: our language simply doesn’t recongize that set of problems, and therefore doesn’t provide primitve constructs to deal with them. The perceived ritual is simply consistency in the approach to solve the problem which is a good thing. Solving each instance of a problem in a unique way will likely lead to ruin.

    I keep coming back to the idea that design patterns are established to deal with the limitations or weaknesses in a language. The Observer pattern is a case in point: in .NET, we have first-class events and delegates, and so the traditional, verbose pattern to realize this pattern isn’t relevant anymore. It’s been absorbed and integrated into languages like C# and VB as a first-class construct. Aspect Oriented Programming, another style or paradigm, is really an anti-style, because as a form of “monkey-patching” , it provides a way to modify existing assemblies (perhaps also generating new ones) to get around an inherent inability for a language to cleanly specify cross-cutting concerns. With a sufficiently-expressive language, AOP “hacks” wouldn’t be necessary.

    As far as overhead, it depends what you mean. If you mean performance overhead I think we need to look at this issue from the perspective of the exponential growth of processing power per dollar rather than pure performance. Even when Moore’s Law fails to double the number of transistors per dollar each year, some new paradigm shift will come along to pick up where the last driving force left off (Ray Kurzweil on demonstrates this trend convincingly). If we give up a few extra milliseconds here and there, the tradeoff is that we make huge gains in developer productivity, and ultimately the development time is what’s expensive these days, not processing power.

    If you mean the cognitive or learning overhead, however, perhaps you have a point there. If you give developers more expressive power, their solution implementations will be more coherent; but the learning curve to understand concepts like currying, immutable values, and monads is considerable. These are the brush strokes of the painter, and we have to learn how to make the individual strokes well before we can start putting them all together to paint a whole landscape. I don’t think this is a bad thing to ask or expect of tomorrow’s developers. It will set a standard for people to aspire to, challenging them and raising the bar in terms of software engineering expertise and quality.

    My ultimate point is, I believe, in agreement with what you’re saying: that functional programming is a good addition to our repetoire of existing skills, not a replacement. It gives us a powerful way to express and compose the functional aspects of software systems in ways that haven’t been available in non-FP-centric languages. The more tools we have at our disposal, the easier it will be to find the right one to achieve our goals.

    FP, AOP, or any other trend may be the new posh thing, as you say. When something new emerges, the best way to famiiarize ourselves with it and determine is applicability is to experiement with it, to use it. If it’s a fad, we’ll likely drop it because of the overhead. But I think it’s grown in popularity (over many years, as you mentioned) because it *does* have real value in solving certain classes of problems. In the same way, I could say “Generics aren’t the solution to everything,” but that doesn’t mean we should program in languages without them. If we don’t need those features to implement a feature, we don’t use them. In the same way, if we don’t need to curry or use monads, then we’ll quickly learn not to. But in those edge cases where it is the right tool for the job, it can be *extremely* useful to have that option.

  4. Dan Vanderboom said

    Amanda, as far as the syntax of F# being a step forward, I absolutely agree. A step forward, not to the side, and thus the reason I advocate adding similar syntax to existing languages. I’m for the inclusion of additional syntax, but because this is such a slow process, the only way to move forward quickly enough is by introducing a brand new language with no legacy.

    Thanks for sharing your thoughts.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: