4 ms·
I'm not the OP, but higher-order functions in Rust are a leaky abstraction. Internally, functions are implemented as closures which might capture ownership and
by fmap 10y ago
I'm not the OP, but higher-order functions in Rust are a leaky abstraction. Internally, functions are implemented as closures which might capture ownership and potentially duplicate/destroy variables in their scope. This means that there is no single function type in rust, there are several for "use once closures" (which capture ownership of a variable and potentially deallocate it), "linear closures" (which you can't duplicate), "non-linear closures" (normal functions), toplevel functions without environments, closures which allow borrows from their environment to escape, etc.
Which one of these categories your function falls into is a decision of the compiler and might change if the borrow checker improves/regresses.
---
These things are pretty much non-issues unless you make heavy use of higher-order programming. For simple second-order functions such as map/filter/fold it's still easy to wrap your head around all of this. However, experience in Haskell has shown that higher-order functions are a very useful abstraction and if their usage is lightweight and intuitive they pop up all over the place. For instance, parser combinators frequently involve fourth-order functions. At this point you do not want to think about the implementation details that your compiler has to fill in.
At this point, I'm afraid that we will not see a lot of elegant higher-order prorgamming in Rust, because it is potentially so difficult to keep track of the ownership story. I'd be happy to be proven wrong, though. :)
- steveklabnik 10y ago> Internally, functions are implemented as closures which might capture ownership This seems backwards. Closures are implemented as a struct for the environment, plus a method on that struct that represents the function call. This then ends up the exact same way as any other function or method call in Rust: with taking self by value, by reference, or by mutable reference.
- fmap 10y agoThe environment contains references/copies/borrows of local variables, depending on a number of conditions on the code. Since the environment struct is generated by the compiler, this is different from a method call where you specify the struct yourself.
- steveklabnik 10y agoIt's still fundamentally sugar; on nightly, you could write it all yourself.
- fmap 10y agoWhat exactly are you arguing for? Closures can be implemented using closure conversion as a derived form in most languages. That's how you compile the code in the first place... The point is that you reason about closures as ordinary functions with local assumptions. You don't need to know how they are implemented at all. On the other hand, in Rust you need to be aware of the implementation in order to use higher-order functions effectively.
- steveklabnik 10y agoI'm arguing that the statement I quoted in my above comment is incorrect; closures are implemented with functions, not the other way around.