3 ms·
I think the reason why is two fold. 1) The type system is focused on mathematical types as opposed to compiler tags. Mathematical types are about ensuring tha
by Verdex 8y ago
I think the reason why is two fold.
1) The type system is focused on mathematical types as opposed to compiler tags. Mathematical types are about ensuring that a function will not fail. Compiler tags are about ensuring that you generate the correct asm op codes. Mathematical type systems allow you to have an easier time knowing the code works.
2) Algebraic data types provide both an AND component and an OR component. That is, you can do type X = A of int * int * int; AND you can do type X = A of int | B of char;. C# style languages provide you with the AND component (class A { public int B => ...; public int C => ...; }). However, they don't provide the OR component. You can create it by constructing weird type hierarchies, but this isn't idiomatic AND it also isn't closed. With an algebraic data type you can know that all of the cases are handled in a match. This isn't something you can ensure in C# (at least not naturally or easily).
Ultimately, I don't think functional programming provides anything that has to be better than object oriented programming. It's just that there are two facilities that tend to go with functional programming that allows a better way to model the problems that we encounter.
- willtim 8y agoMissing from your list is arguably the most important difference: programming with mathematical (immutable) values. This allows one to build very high-level abstractions and easily reason about correctness. OOP languages simply were not designed for this style of programming. There are also many other significant differences. I estimate I am about ten times more productive in Haskell than Java.
- Verdex 8y agoI don't think mutability is problematic. The problem with mutability is that you can create hidden communication channels between different sections of your code and it can be very difficult to determine what is actually going on without carefully analyzing the entire code base at compile time and at run time for every possible input. So if you only have mutability inside of a function and it cannot escape, then you have no problems. Or if you have a way to prevent it from crossing module boundaries. Rust for example, gives you some pretty good tools for controlling mutability and for tracking it. I think this is actually superior to a fully immutable system as with full immutability you end up with other weird problems (like needing monads and monad transformers to do things that would otherwise be simple).
- willtim 8y agoSure, there's nothing wrong with pure functions that encapsulate mutation, even Haskell supports this, but this isn't how OOP typically works. OOP developers actually use mutation to model the real world, for example a bank balance! Many of their APIs and libraries are designed around mutation, even the default containers. Java got String right though (apart from the UTF16 part).
- Verdex 8y agoStrong agree on the "but this isn't how OOP typically works" part. I think one of the reasons that Rust doesn't have a traditional OO model is because you can't actually enforce mutability controls in that way. At the very least, when I tried to think of how I would find a way to enforce mutable and immutable data using java / c# style OO, I couldn't think of a way that wasn't kind of crazy or hard to use. On the other hand, structs with traits is actually pretty easy to enforce immutable data (hey, this requires a mutable borrow and what you have is an immutable borrow, so compile error).