Hacker News new | past | comments | ask | show | jobs | submit login

The main use of closures today is to create something you can pass to a callback. In theory, you could pass an object, but the callback would have to cooperate by accepting an object and an object method, or a reference to an object method/object pair, in languages which support that. This requires more standardization than one is likely to get.



> This requires more standardization than one is likely to get.

Not for the functionality - the only difference is that your compiler cannot tell you that you are doing it wrong while a strict interface can be checked at compile time. But the standardization is there, it's just not explicit - your programm will crash/fail when you don't provide a proper callback that obeys the implicit contract (e.g.: takes 2 arguments, first the value, second the error if any; returns nothing).


> the only difference is that your compiler cannot tell you that you are doing it wrong while a strict interface can be checked at compile time

In most compiled languages with closures, the parameters are type-checked. In some, the return type is also type checked, but there are typically ways to add type checking to the return type if that's important.


I used a closure for a callback less than 1% of the time. Closures are .. closed pieces of information to be combined (through apply). See untyped monadic style, or lc-encoding of lists, functional composition (f . g => a new function, not a value).

I closely related closures to partial application. But mostly.. closures are anonymous objects tiles, you can create one on the fly as needed without cruft.


I think of closures as a bit orthogonal to that; the definition of "closure" that I'm used to is a function that "encloses" some data that is not an argument (somewhat like a function with free variables in lambda calculus), whereas a callback might only deal with its arguments. That being said, sometimes I see the term "closure" being used in a way that I associate with the word "lambda", which feels a bit off to me (I'm looking at you, Rust...)


Lua creator Roberto Ierusalimschy just gave a talk about "Functions in Lua" and starts his talk explaining that our (conversational) language has still not evolved a precise way to articulate all these different ideas about functions.

On his first slides, he shows the words, "anonymous functions", "lambdas", "closures", "function values", and "first-class values", and shows how each has subtly different meanings/implications and tends to take us down different lines of thinking which affects the conversation you are trying to have with somebody else.

https://www.youtube.com/watch?v=wdRGOE1N-FA


A lambda is an anonymous function. A closure is a function which carries with it some state. The two concepts are independent - you can have named functions as closures, and lambdas that aren't closures. Rust does seem to tie the concepts together syntactically.

Languages which support nested functions usually allow those inner functions to be closures.


This is my understanding of what the terms mean as well, but in Rust, any anonymous function seems to be referred to as a "closure"[1], which is what feels strange to me.

[1] See the first example here (which only operates on its arguments but is still referred to as a closure): https://doc.rust-lang.org/book/closures.html


Yeah, any time you have a nested function you raise the question of "what can this close over?" Sometimes the answer is "nothing", and that's not a closure... but it's still an answer to the question so it makes some sense to talk about it in the same breath.


Lambdas are just functions with different syntax. Closures imply keeping some state around, and may require that some variables from outer scopes live longer than they otherwise would. (That's what they're usually used for in Javascript, where you want state kept around for a reply event.)

Closures are easy to implement in garbage-collected languages, but get complicated in non-garbage collected languages. When an inner function normally references variables in an outer scope, they're just references to the stack. But if there's a closure that can outlive the outer scope, those variables have to be saved somewhere.

With C++11 closures, you have to specify what you want to keep around and how you want it kept.[1] Internally, C++11 creates an object to store the variables you want to keep around. This can potentially create lifetime problems, because you can save a reference to a variable, then keep the closure object around longer than the variable being referenced. This creates a dangling pointer. Rust has lifetime checking to catch such errors, but C++11 does not. See this Stack Overflow discussion of how not to shoot yourself in the foot with C++11 closure lifetime undefined behavior.[2]

That's why it's useful to realize that closures and lambdas are not the same thing. Lambdas are simple. Closures are complicated.

[1] http://www.cprogramming.com/c++11/c++11-lambda-closures.html [2] http://stackoverflow.com/questions/27775233/lambdas-and-capt...


I certainly don't mean that there aren't contexts where distinguishing the two is vital to understanding. I just mean there are context where you'll need to talk about both, and I think that's part of the reason they sometimes get conflated.


Rust's closures are, well, closures. But many of them are effectively lambdas. It's not like we can force you to refer to your environment or something :p

"A closure with an empty environment" vs "a lambda" is a fine, barely-existent line. Or arguably identical.


Wait, what? A closure can be a lambda and a lambda can be a closure, but you can have closures that aren't lambdas and lambdas that aren't closures. Why link them together at all? "A closure with an empty environment" is only a lambda if it's unnamed, otherwise it's just a function.


I think the burden of proof is the opposite: why not link them together? What are the benefits of having closures and lambdas be two distinct language features when having just one seems to suffice (specifically, having a lambda be a degenerate closure)? As for naming, that's an orthogonal issue, as a closure can be anonymous just as easily, and I see no use in drawing a semantic distinction between anonymous "lambdas" and nonymous "functions".


What on earth are you talking about? The definition of "lambda" is "anonymous function." Naming is orthogonal to closures, yes, but it's the entire difference between a lambda and any other kind of function. A lambda can close over state or not, it doesn't matter. It just needs to not have a name. So if naming is orthogonal to closures, then lambdas are orthogonal to closures, and then it makes no sense to compare them.


> The definition of "lambda" is "anonymous function."

> A lambda can close over state or not, it doesn't matter.

I've never heard of any definition of "function" that allows closing over state, that's the demarcation that we use to distinguish a function from a closure. What taxonomy are you trying to propose? And going back to my original question, what is the practical intent of trying to make a lambda a semantically-distinct concept from a closure?



In the phrase "anonymous function", "function" means anything that you can call. This includes closures. I'm very surprised you've never heard of the word "function" being used that way.


I guess in my mind, "a closure with an empty environment" is a contradiction, but as mentioned elsewhere in the thread, there isn't a lot of consistency to the way we use these types of terms (closure, lambda, etc.) across different languages and paradigms.


Yup. I also think it matters if you come at it from an implementation angle or a math angle. It's a contradiction from the latter, but from the former, it may not be.

Maybe I'll write a blog post.


Callbacks only deal with their arguments, but almost every callback I see in the wild has a first argument "void * cookie" which immediately gets typecast into a pointer to the structure (oops, I mean object) being manipulated.


Right, that's how you do it in C, where you don't have closures. Closures take some heavy machinery behind the scenes in a hard-compiled language. They sort of fall out of the dynamic binding mechanism in Python and Javascript.


I'm confused by your terminology here. Doesn't "callback" usually just mean a first class function f you pass around - as a piece of data - to another function g, under the assumption that g calls f?

Ie

    function f(...) {...}
    g(f);

It looks like you're using "callback" to refer to "g" in my example, not "f". Is my terminology wrong, or is yours?

(This is a genuine terminology question, not an exercise in pedantry.)


Sorry, meant "callback argument", a function argument to which a function can be passed.

In Javascript and Python, all functions passed as parameters to other functions are potentially closures, but this is not the case in most compiled languages.


No worries. The callback terminology always confused me. I think it came from the C culture, where you need a special word for a tricky concept. Weird that it persists in javascript, where it's easy.


Or you can pass a reference to some object's method.


If that's supported in the language, yes. C++ supports this, but the syntax is special.[1] What's passed is not just a pointer to a function; it's really two pointers, one for the function and one with the "this" pointer.

[1] http://umich.edu/~eecs381/handouts/Pointers_to_memberfuncs.p...


note that, in C++, pointers to member functions do not close over 'this' [1], so they are not really a reference to a method of an object, i.e. you need to provide the actual object externally to invoke the pmf.

The closure need to be created explicitly with something like std::bind or an actual lambda, and passed around as an std::function (a type erased, generic closure wrapper) or as a template parameter.

/pedantic

[1] GCC does have a very old extension that actually creates the closure.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: