Live data from Hacker News

A guide to closures in Rust

hashrust.com

51–60 of 102 posts

Re: A guide to closures in Rust

#51
post #43

Earlier quoted context omitted.

If you want to do anything with the closure it gets a little tricker, for example if you did something naive like fn fn_that_takes_closure (f: fn (i32, 3i2) -> i32) { ... } let x = |a, b| a + b; fn_that_takes_closure(x); That would not compile, because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Every closure in Rust has a unique anonymous type, which means if you want…

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

Isn't the distinguishing feature of a closure that it can capture stuff from the environment?

> Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

> The term closure is often used as a synonym for anonymous function, though strictly, an anonymous function is a function literal without a name, while a closure is an instance of a function, a value, whose non-local variables have been bound either to values or to storage locations (depending on the language; see the lexical environment section below).

My understanding is that your use of 'capture' matches up with the the use of 'bound' in the description above.

https://en.wikipedia.org/wiki/Closure_(computer_programming)

Re: A guide to closures in Rust

#52
post #43

Earlier quoted context omitted.

If you want to do anything with the closure it gets a little tricker, for example if you did something naive like fn fn_that_takes_closure (f: fn (i32, 3i2) -> i32) { ... } let x = |a, b| a + b; fn_that_takes_closure(x); That would not compile, because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Every closure in Rust has a unique anonymous type, which means if you want…

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

If it doesn't capture anything, then it's not a closure.

Re: A guide to closures in Rust

#53
post #43

Earlier quoted context omitted.

If you want to do anything with the closure it gets a little tricker, for example if you did something naive like fn fn_that_takes_closure (f: fn (i32, 3i2) -> i32) { ... } let x = |a, b| a + b; fn_that_takes_closure(x); That would not compile, because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Every closure in Rust has a unique anonymous type, which means if you want…

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

Closing over variables is the thing that makes it a closure. Otherwise, you just have an anonymous function. A closure is a function plus the captured environment.

The difference is meaningful here. You have to allocate a closure (and deal with its lifetime and the lifetimes of the variables it references) but the anonymous function is just a pointer to static code in the binary. That's the entire difficulty with closures in non-GC languages.

This distinction matters less in GC languages where you're not thinking about lifetimes either way.

Re: A guide to closures in Rust

#54
> A closure is like an anonymous function.

I like the article overall, but I have a bit of a pedantic note about this opening line.

Using "like" suggests that there is some similarity that can be used to understand one thing from the other, but in truth these are two distinct (though related) technical terms, and I think phrasing this relationship as a simile may actually obstruct understanding rather than enable it.

An anonymous function is just a function without a name. There's nothing particularly exciting about that, except that they only really make sense as a concept within the context of a language with first-class functions (i.e., a language where functions are values that can be passed around as arguments and such).

A closure is a function paired with an environment. Technically (meaning "in the academic literature"), this can be any function at all --- named functions can be used to create closures. But in Rust this is not the case, since they only use the term in connection with anonymous functions. This is actually addressed in the first couple of lines of the Rust Book's entry on closures [1].

Saying "a closure is like an anonymous function" would be like me saying "a car is like a set of four wheels". While it is true that the four wheels are integral to the car's identity, it is not the case that these things are directly similar in the way that the word "like" suggests they are.

[1] https://doc.rust-lang.org/book/ch13-01-closures.html

Re: A guide to closures in Rust

#55

> A closure is like an anonymous function. I like the article overall, but I have a bit of a pedantic note about this opening line. Using "like" suggests that there is some similarity that can be used to understand one thing from the other, but in truth these are two distinct (though related) technical terms, and I think phrasing this relationship as a simile may actually obstruct understanding rather than enable it.…

I would further elaborate on your point by saying that as someone who likes to hang out on programming fora and help people as I was helped when I was young, this terminology confusion causes real confusion in the field as well.

Many programmers-in-training find it confusing as to why whether or not a function has a name seems to be tied to whether or not it has an environment (not that they phrase it that way but that's what it boils down to), and my usual answer is to explain something much like your post; the resolution is, there is no such connection. I have fielded this question in one form or another many times.

"Anonymous function" should not be used as a synonym for "closure". Generally I will follow along with the dominant language terminology if I am clearly in the context of a very particular language, but may include why I don't like the language community's terminology if it helps my point.

Re: A guide to closures in Rust

#56
post #52

Earlier quoted context omitted.

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

If it doesn't capture anything, then it's not a closure.

There’s so much confusion out there due to people throwing out the term “closure” imprecisely, ugh

Re: A guide to closures in Rust

#57
post #51

Earlier quoted context omitted.

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

Isn't the distinguishing feature of a closure that it can capture stuff from the environment? > Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope. > The term closure is often used as a synonym for anonymous function, though strictly, an anonymous function is a funct…

It can capture things, OP's example does not capture anything.

Re: A guide to closures in Rust

#58
post #51

Earlier quoted context omitted.

> That would not compile It does compile. > because `x` does not have the type `fn (i32, i32) -> i32` (that's reserved for "normal" functions). Closures can cast to function pointers just fine as long as they don't capture anything.

Isn't the distinguishing feature of a closure that it can capture stuff from the environment? > Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope. > The term closure is often used as a synonym for anonymous function, though strictly, an anonymous function is a funct…

people casually using the term closure for anonymous functions has caused so much confusion over the years lol

Re: A guide to closures in Rust

#59

> A closure is like an anonymous function. I like the article overall, but I have a bit of a pedantic note about this opening line. Using "like" suggests that there is some similarity that can be used to understand one thing from the other, but in truth these are two distinct (though related) technical terms, and I think phrasing this relationship as a simile may actually obstruct understanding rather than enable it.…

In some language all functions capture their environment, making that original statement more true than you make it out to be.

Personally I think the term closure should be banned, because it only adds confusion.

There are just functions, some named some anonymous, some capturing the environment, some not, some being disallowed by some constraints from the host language. The term closure cuts through this space in a useless and rather ad-hoc way.

Post reply on HN