6 ms·
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
by duped 3y ago
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 to do anything with them besides calling them, you need to understand `Fn`, `FnOnce`, and `FnMut` traits and/or `dyn` trait objects. To write that above you'd need to do something like this:
fn fn_that_takes_closure<F> (f: F)
where
F: Fn(i32, i32) -> i32
- proto_lambda 3y ago> 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.
- abeppu 3y agoIsn'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) https://en.wikipedia.org/wiki/Closure_(computer_programming)
- proto_lambda 3y agoIt can capture things, OP's example does not capture anything.
- evntdrvn 3y agopeople casually using the term closure for anonymous functions has caused so much confusion over the years lol
- xigoi 3y agoIf it doesn't capture anything, then it's not a closure.
- evntdrvn 3y agoThere’s so much confusion out there due to people throwing out the term “closure” imprecisely, ugh
- electroly 3y agoClosing 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.
- kangalioo 3y agoAs per Rust reference, even a capture-less closure is a closure and distinct from an anonymous functions. Also, your arguments only partly apply in Rust. Rust doesn't heap-allocate closures. And you also often don't have to deal with lifetimes - a closure that captures variables by move or copy is perfectly self-contained The difference between a closure that captures and a closure that doesn't is like the difference between `(T)` and `()` - same kind of thing, so it adheres to the same terms and behaviors
- sapiogram 3y ago> You have to allocate a closure That's incorrect, a closure in Rust compiles down to a static function that takes its environment as an argument. None of that requires a heap allocation in the above code.
- Georgelemental 3y agoStack allocation is still allocation.
- smabie 3y agoLiterally no considers that to be the case? Like I have never met anyone who would consider declaring an integer variable "allocation"
- 3y ago
- kangalioo 3y agoOther comments are saying non-capturing closures are not closures. If we want to have this pedantic argument of definitions: proto_lambda is actually right, with Rust's definition of closures. According to the Rust reference: > Closure types > > A closure expression produces a closure value with a unique, anonymous type that cannot be written out. https://doc.rust-lang.org/reference/types/closure.html https://doc.rust-lang.org/reference/types/closure.html Even a non-capturing closure is written using a closure expression and produces a unique, anonymous type.
- tialaramex 3y ago> that's reserved for "normal" functions Function pointers. Rust's functions all have unique anonymous types too. In C or C++ the functions isupper and islower (which are predicates that decide whether a char is an upper or lowercase letter respectively) have the same type. In Rust such functions always have their own unique anonymous type. char::is_uppercase and char::is_lowercase don't have the same type. This has a consequence when we want to use a functional-like specialisation. For example "Walter White".starts_with(char::is_uppercase) isn't just passing a function pointer - that can't work, what happens instead is there's an implementation of Pattern on things which match a certain FnMut trait, these two function types match that trait, therefore Pattern is implemented for each type, so there's a monomorphization step, baking a custom implementation of this function for this specific predicate, if you use a different predicate you get a different monomorphization.