10

Many modern programming languages support some concept of closure, i.e. of a piece of code (a block or a function) that

  1. Can be treated as a value, and therefore stored in a variable, passed around to different parts of the code, be defined in one part of a program and invoked in a totally different part of the same program.
  2. Can capture variables from the context in which it is defined, and access them when it is later invoked (possibly in a totally different context).

Here is an example of a closure written in Scala:

def filterList(xs: List[Int], lowerBound: Int): List[Int] =
  xs.filter(x => x >= lowerBound)

The function literal x => x >= lowerBound contains the free variable lowerBound, which is closed (bound) by the argument of the function filterList that has the same name. The closure is passed to the library method filter, which can invoke it repeatedly as a normal function.

I have been reading a lot of questions and answers on this site and, as far as I understand, the term closure is often automatically associated with functional programming and functional programming style.

The definition of function programming on wikipedia reads:

In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state.

and further on

[...] in functional code, the output value of a function depends only on the arguments that are input to the function [...]. Eliminating side effects can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming.

On the other hand, many closure constructs provided by programming languages allow a closure to capture non-local variables and change them when the closure is invoked, thus producing a side effect on the environment in which they were defined.

In this case, closures implement the first idea of functional programming (functions are first-class entities that can be moved around like other values) but neglect the second idea (avoiding side-effects).

Is this use of closures with side effects considered functional style or are closures considered a more general construct that can be used both for a functional and a non-functional programming style? Is there any literature on this topic?

IMPORTANT NOTE

I am not questioning the usefulness of side-effects or of having closures with side effects. Also, I am not interested in a discussion about the advantages / disadvantages of closures with or without side effects.

I am only interested to know if using such closures is still considered functional style by the proponent of functional programming or if, on the contrary, their use is discouraged when using a functional style.

7
  • 5
    In a purely functional style/language, side effects are impossible... so I guess it would be a matter of: at what level of purity does one consider code to be functional? Nov 7, 2012 at 20:10
  • @SnOrfus: At 100%?
    – Giorgio
    Nov 7, 2012 at 20:12
  • 2
    Side effects are impossible in a purely functional language, so that should answer your question. Nov 7, 2012 at 20:32
  • @SnOrfus: In many languages closures are considered a functional programming construct, so I was a bit confused. It seems to me that (1) their usage is more general than just doing FP, and (2) using closures does not automatically guarantee one is using a functional style.
    – Giorgio
    Nov 7, 2012 at 20:40
  • Can the downvoter leave a note on how to improve this question?
    – Giorgio
    Jun 24, 2013 at 22:31

3 Answers 3

9

No; the definition of functional paradigm is about lack of state and implicitly lack of side-effects. It is not about high-order functions, closures, language supported list manipulation or others language features...

The name of functional programming comes from the mathematical notion of functions - repeated calls on the same input always gives the same output - nullipotent function. This can only be achieved if the data is immutable. In order to ease development, the functions became mutable (functions change, data is still immutable) and thus the notion of higher-order functions (functionals in mathematics, as derivatives for example) - a function that takes as input another function. For the possibility of functions to be carried around and passed as arguments, first-class functions were adopted; following these, to further enhance productivity, closures appeared.

This is, of course, a very simplified view.

5
  • 5
    Higher-order functions have absolutely nothing to do with mutability, neither do first-class functions. I can pass around functions and construct other functions from them in Haskell with great ease, without having any mutable state nor side effects.
    – tdammers
    Nov 7, 2012 at 21:59
  • @tdammers I probably did not express very clearly; when I said functions became mutable I did not refer to data mutability but to the fact that the behavior of a function can be be changed (by a high-order function).
    – Random42
    Nov 7, 2012 at 22:24
  • 1
    A higher-order function doesn't have to change an existing function; most textbook examples combine existing functions into new functions without modifying them at all - take map, for example, which takes a function, applies it to a list, and returns a list of the results. map does not modify any of its arguments, it doesn't change the behavior of the function it takes as an argument, but it is definitely a higher-order function - if you apply it partially, with just the function parameter, you have constructed a new function that operates on a list, but still no mutation has happened.
    – tdammers
    Nov 7, 2012 at 22:28
  • @tdammers: Exactly: mutability is only used in imperative or multi-paradigm languages. Even though these can have the concept of a higher-order function (or method) and of a closure, they give up immutability. This can be useful (I am not saying one should not do it) but my question is whether you can still call this functional. Which would mean that, in general, a closure is not a strictly functional concept.
    – Giorgio
    Nov 8, 2012 at 6:28
  • @Giorgio: most of the classic FP languages do have mutability; Haskell is the only one I can think of off the top of my head that doesn't allow mutability at all. Still, avoiding mutable state is an important value in FP.
    – tdammers
    Nov 8, 2012 at 16:14
11

No. "Functional-style" implies side-effect-free programming.

To see why, have a look at Eric Lippert's blog entry about the ForEach<T> extension method, and why Microsoft didn't include a sequence method like it in Linq:

I am philosophically opposed to providing such a method, for two reasons.

The first reason is that doing so violates the functional programming principles that all the other sequence operators are based upon. Clearly the sole purpose of a call to this method is to cause side effects. The purpose of an expression is to compute a value, not to cause a side effect. The purpose of a statement is to cause a side effect. The call site of this thing would look an awful lot like an expression (though, admittedly, since the method is void-returning, the expression could only be used in a “statement expression” context.) It does not sit well with me to make the one and only sequence operator that is only useful for its side effects.

The second reason is that doing so adds zero new representational power to the language. Doing this lets you rewrite this perfectly clear code:

foreach(Foo foo in foos){ statement involving foo; }

into this code:

foos.ForEach((Foo foo)=>{ statement involving foo; });

which uses almost exactly the same characters in slightly different order. And yet the second version is harder to understand, harder to debug, and introduces closure semantics, thereby potentially changing object lifetimes in subtle ways.

6
  • 1
    Although, I agree with him... his argument weakens a bit when considering ParallelQuery<T>.ForAll(...). The implementation of such an IEnumerable<T>.ForEach(...) is extremely useful for debugging ForAll statements (replace the ForAll with ForEach and remove the AsParallel() and you can much more easily step through/debug it) Nov 7, 2012 at 20:14
  • Scala does not enforce purity either: you can pass a non-pure closure to a high-order function. My impression is that the idea of a closure is not specific to functional programming but it is a more general idea.
    – Giorgio
    Nov 7, 2012 at 20:34
  • 7
    @Giorgio: Closures don't have to be pure to still be considered closures. They do have to be pure, however, to be considered "Functional Style." Nov 7, 2012 at 20:38
  • @Robert Harvey: This seems to make a lot of sense (+1). The motivation of my question is that I have been reading lots of posts that seem to go in the opposite direction. Like: Java needs functional programming support -> Java needs proper closures -> current Java closures are not good enough (for FP) because they can only capture final variables (besides having a verbose syntax). Or, C++ supports FP in the form of closures that capture local variables by reference, etc. It seems to be commonplace that these constructs support FP, which (as useful as they can be) they do not.
    – Giorgio
    Nov 7, 2012 at 20:51
  • 3
    @Giorgio: It's really useful to be able to make a closure around mutable state and side effects and pass it to another function. It's just contrary to the goals of functional programming. I think that a lot of confusion comes from elegant language support for lambdas being common in functional languages. Nov 7, 2012 at 21:37
0

Functional programming take first class functions to the next conceptual level for sure, but declaring anonymous functions or passing functions to other functions is not necessarily a functional programming thing. In C, everything was an integer. A number, a pointer to data, a pointer to a function... all just ints. You could pass function pointers to other functions, make lists of function pointers... Heck, if you work in assembly language, functions are really just addresses in memory where blocks of machine instructions are stored. Giving a function a name is extra overhead for the people who need a compiler to write code. So functions were "first-class" in that sense in a completely non-functional language.

If the only thing you do is calculate mathematical formulas in a REPL, then you can be functionally pure with your language. But most business programming has side effects. Losing money while waiting for a long-running program to complete is a side effect. Taking any external action: writing to a file, updating a database, logging events in order, etc. requires a change of state. We could debate about whether state is really changed if you encapsulate these actions in immutable wrappers that push side-effects off so that your code doesn't have to worry about them. But it's like discussing whether a tree makes a noise if it falls in the forest with no-one there to hear it. The fact is that the tree started upright and ended up on the ground. State gets changed when stuff gets done, even if only to report that the stuff got done. True purity in functional programming is only fully realized in isolated sections of code or on paper - not in real, useful programs as a whole.

So we are left with a scale of functional purity, not black and white, but shades of gray. And on that scale, the fewer side effects, the less mutability, the better (more functional).

If you absolutely require side effect or mutable state in your otherwise functional code, you strive to encapsulate or it from the rest of your program as best you can. Using a closure (or anything else) to inject side effects or mutable state into otherwise pure functions is the antithesis of functional programming. The only exception might be if the closure were the most effective way to encapsulate the side effects from the code it is passed to. It's still not "functional programming" but it might be the closet you can get in certain situations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.