4 ms·
> Anyways, I guess this gets easier over time, right? Yes. > Should I avoid using closures all over the place? Not necessarily. > Should my code look more l
by ragnese 6y ago
> Anyways, I guess this gets easier over time, right?
Yes.
> Should I avoid using closures all over the place?
Not necessarily.
> Should my code look more like C and less like Haskell?
Yes. Others sometimes don't like to hear this, but IMO, Rust is not at all functional. Passing functions around is not ergonomic (how many function types does Rust have again? Three?). Even making heavy use of Traits, especially generic ones, is difficult.
Rust is very much procedural. Java-style OOP doesn't work because of the borrowing/ownership. And FP style function composition doesn't work without Boxing everything. But then you'd need to be careful about reference cycles.
- vmchale 6y ago> how many function types does Rust have again? Three? It has to, right? ATS has many function types as well, plus stack-allocated closures (I think Rust has that too??)
- steveklabnik 6y agoRust's closures do not heap allocate unless you box them, like any other struct, because closures are sugar for a struct + a function, that's correct. (and yes, there are three types of closures, because they need to know if they take said struct by reference, by mutable reference, or by owner.)
- ragnese 6y agoIt does have to, because of the way mutation and ownership work. Which is great! But it makes functional programming awkward. The language does not "steward" you toward function composition.
- estebank 6y ago> how many function types does Rust have again? Three?). Depending on what you meant, there are more than three: * There are 3 traits, used by closures depending on their needs: * Fn(Args) -> Output * FnMut(Args) -> Output * FnOnce(Args) -> Output * *Every* `fn` is its own type (`fn() {foo}`) * Function pointers (`fn()`), which is how you pass the above around in practice > Rust is very much procedural. I think this is like saying Python is very much procedural: true, but loses some nuance. Rust has some attributes of OOP, some attributes of FP. Some constructs from OOP and FP are made harder once you involve borrowing. Saying it is procedural conjures images of Pascal and K&R C in people's minds. To bolster your argument, though, I mostly use method chaining for iterators but every now and then I need to turn it into a `for` loop to keep the lifetimes understandable for the compiler, myself and others.
- ragnese 6y agoI realized after I wrote the comment that I was really referring to the closure traits when I said that. And I really should have said "kind" instead of "type" because, like you said, every different function has its own type. But anyway, I don't really disagree with your point about categorizing languages as OOP, Procedural, or Functional. But honestly, in this case, I think it's pretty damn clear than Rust is procedural WAY more than it's either OOP or FP. (Note: By OOP, I mean Java-style with tall ownership hierarchies and object-managed mutable state, not necessarily caring about inheritance. And definitely not referring to Alan-Kay-Style-OOP a la Lisp and Smalltalk). Scala can be looked at as FP and/or OOP. C++ can be looked at as Proc and/or OOP. Python, IIRC, can kind of do all of them, but I don't remember it being easy to make copies/clones in Python, so FP is questionable. Have you ever tried to write two versions of a complex async function in Rust? One with async and one with Futures combinators? Due to ownership, the Futures combinators approach very quickly devolves into a nightmare. The language doesn't "want" you to do that. What about function composition? Very awkward to do with matching up the different Fn traits. And deeply nested object hierarchies are a no-go, too, because of the inability to do "partial borrows" of just a single field of a struct. I mean, yes, it's not C because it has a real type system and generics. But... it's pretty much C in that you just write functions and procedures that operate on structs. EDIT: Perhaps my "hardline" approach on calling Rust procedural is in response to people who have come to Rust from non-FP languages, see `map`, `filter`, and `Option` and start calling Rust functional. That's not functional programming! Ask someone who does OCaml to try out Rust and see if they call Rust functional afterwards.
- noctune 6y ago>And deeply nested object hierarchies are a no-go, too, because of the inability to do "partial borrows" of just a single field of a struct. I'm not totally sure if this is what you mean, but FYI you can borrow multiple fields mutably using destructuring: struct Foo(u8, u8); fn main() { let mut bar = Foo(1, 2); let Foo(ref mut x, ref mut y) = &mut bar; *x += 1; *y -= 1; println!("{} {}", bar.x, bar.y); }
- 6y ago
- int_19h 6y agoI think that Rust is often assumed to be functional because it has ADTs and nice pattern matching, both of which have historically been a feature specific to FP. Just goes to show how fuzzy our definition of FP really is...
- ragnese 6y agoAgreed. Same with "OOP". Who the hell knows what people really mean when they say that. Those people who think that "FP" means "type system like Haskell" are wrong, though, IMO. It precludes languages that are much more function-based, such as Clojure, Schemes, Elixir.
- wtetzner 6y agoFunctional in my mind more or less means means working with immutable values.
- scns 6y agoUsually when the term OOP is used, it actually means ClassOrientedProgramming (C++/Java/C# etc)
- ragnese 6y agoWhich I also don't understand. Is that a style of overusing classes where functions would suffice (FooHelper)? Or is it something about the language? Because almost all popular languages have classes. Rust and Go call them "struct", but it's the same thing. Swift has "class" and "struct", but they're both the same thing as a C++ class.
- iopq 6y agoRust structs are not classes. Rust puts structs inline (on the stack), classes are virtual. Since Rust is a systems programming language, it's an actual distinction that makes a difference
- 6y ago