Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

"the most popular languages that are in use right now don't support closures (Java, C++)"

That is blatantly wrong. Closures, that is, the implementation structure which stores along with a code pointer the references or values to which local variables referenced by said code are bound, have been in Java since version 1.0. Otherwise you could not write code such as:

class foo { final static int bar = 6; static class baz { int bla() { return bar; } } }

and expect "(new foo.baz()).bla()" to return 6.

What Java is missing (and I suspect what the author is conflating closures with) are anonymous functions, which require closures to function properly for the same reason inner classes require closures.

Closures are not anonymous functions. Closures are an implementation detail which allow anonymous functions (among other structures) to act as expected in statically-scoped languages.

Scheme has anonymous functions and closures.

Java does not have anonymous functions but does have closures.

Emacs Lisp has anonymous functions but does not have closures (and thus does not exhibit static scope).

BASIC has neither anonymous functions nor closures.

(It is worthwhile to note that there are other methods for implementing static scope such as alpha-renaming but they are usually much less efficient than closures.)



Plus, Java does have anonymous inner classes, which can be used in a fashion pretty similar to lambdas although with clumsier syntax than most people would like.

Yours is a crucial point that I think got munged in the Java 7 closures debate, since a lot of Java people didn't know what closures were, and a lot of people on the outside maybe didn't know what Java lacked or didn't lack, so there were definitely a few blog posts that conflated them with lambdas.


> Closures are an implementation detail which allow anonymous functions (among other structures) to act as expected in statically-scoped languages.

I don't think anonymous functions have anything to do with it. Closures come into play when you are creating a function that has access to local variables from an enclosing scope. This function need not be anonymous. For example, in Lua:

    function x()
      local var = 5
      local function y()
        print(var)
      end
      return y
    end

    y = x()
    y() -- Prints 5.
At no time is the inner function anonymous. When it is created it is bound to the local variable "y" and later it is bound to the global variable "y". And yet it is a closure because it has access to the lexical scope in which it was defined.

Also, if closures were an "implementation detail" it would not make sense to say that a language has or does not have closures, only implementations of a language would have or not have them (and the language user would not be aware of whether the language implementation had closures or not).


Good examples of closures / first order functions in java is through a visitor; example below is like the ones in A Little Java, A Few Patterns

new Top(new Anchovy(), new Top(new Tuna(), new Top(new Lettuce(), new Bot()))) .accept( new RemVisitor(new Anhovy() );

This removes those smelly Anchovies from your tuna sandwich -- and can be implemented with a closure or not. If accept() method returns a new Top w/o Anchovies and RemoveVisitor stores what to remove in its field then it is a closure.

This book is cool for lisp programmers to learn programming with recursive objects like composites and decorators.


What happens if bar is not final and/or not static?


If it's not static you wouldn't be able to reference it from the static context (the inner class baz). It could be non-final though, because it's a field not a local.

The second part is the more interesting part, and is part of what people are talking about when they say that Java doesn't have closures: you can't modify closed over local (stack allocated) variables. However you can call methods that modify or otherwise modify heap-allocated objects, for instance if bar was an array you could modify it's contents, or if it was a Vector you could call addElement() or whatever.

In the GP's case, bar is a member field, not a local, so I don't think it needs to be final, and a quick test checks out. But if those were variables local to a method and you referenced them from an anonymous inner class, they would have to be final.

See: http://c2.com/ppr/wiki/JavaIdioms/ClosuresThatWorkAroundFina...

If I recall correctly, from digging into the famous Guy Steele quote "we were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp." I think this decision was made at the time because programmers didn't like the idea of heap-allocated local primitives. I could be totally off base here though. That wiki page mentions something about preserving the threading model, which sounds reasonable, but I don't know enough about Java's history to be totally clear on the motivation.

edited because I'm a pedant.

and the relevant message from Guy Steele: http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/m... (that whole thread is fascinating, massive respect for GLS as if I didn't already, and helped quell some of my hipster Java hatred.)


Glad you know more about Java than I do :) I never knew about the restriction on mutating local variables in the closure. It's strange to think about that coming from the FP world where all mutable values are references to cells that (conceptually) live on the heap.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: