Recently I have been learning to program in Erlang as a long time C and C# developer. I am fairly new to functional programming. Now, I am trying to understand how do objects in languages like Scala work. I have been taught that OOP is all about changing state of given object using its public methods. Those methods change state of public properties and private members. But now I hear that in functional programming all objects should be immutable. Well, I agree that once assigned variable (in given function) should remain pointing to the same object. But does this "immutability" mean that I cannot change the internals (properties, private members) of given objects using their public methods? This makes objects just like simple data containers. It extracts all of the functionality outside of them. This makes objects act more like structures in C. It is something that is strange to me. Maybe I am missing something? Is it possible to use objects the old-fashioned-way and still consider it as functional programming?
You are mixing up three different concepts. Functional programming, mutability, and OOP are three different things.
I have been taught that OOP is all about changing state of given object using its public methods.
Yes and no. The important thing in OOP is that you have objects, which can simultaneously carry around data and code (their member methods), and that you talk to the objects using their interface, so that the object can then
this
in the method implementation)Nobody prescribes you what this method call does, or that it must modify some state.
It happens to be that OOP helps to restore some basic sanity when working with state. This is because the horrifyingly complex global state of the application can be cut up into smaller pieces and hidden inside mutable objects. Moreover, those mutable objects can additionally attempt to maintain at least some local invariants, by prohibiting direct access to their state, and providing only a restricted set of operations that can modify that state.
But now I hear that in functional programming all objects should be immutable.
They should respect referential transparency. If your objects have no mutable state and only methods without any side effects, then it is sufficient for referential transparency. Sufficient, but not necessary: the objects can have more complex inner structure, but appear completely immutable from the outside. Caching is a good example.
Furthermore, even pure functional programs are not restricted to working with immutable data structures only. There is such thing as pure mutable state. The idea is that your functional programs are used to construct something like complex action plans for dealing with mutable state. The plan itself is an immutable entity. This plan can be very complex, but thanks to the fact that it is built from pure functions, it can be still sufficiently easy to reason about. This plan, which is built using only pure functions, can then be given to a small and simple interpreter, which executes the plan on mutable memory. In this way, you reap the benefits of both worlds: you have conceptual simplicity of pure functions while you are building the plan, but you also have the performance of close-to-the-metal computations when you execute this plan on mutable data structures.
But does this "immutability" mean that I cannot change the internals (properties, private members) of given objects using their public methods?
In general, yes. However, in Scala, immutability is not enforced by default. You can decide what parts of your application are complicated enough to reason about, so that it might be worth it to restrict yourself to pure functions. Everything else can be implemented using ordinary mutable structures, if this is easier.
This makes objects just like simple data containers. It extracts all of the functionality outside of them.
No, because objects still carry their virtual dispatch table with them. You can then ask the object from the outside to invoke the method apply(integer i)
, and the object, depending on what kind of object it is, might then invoke completely different things, like
/** get i-th character */
String.apply(integer i)
or
/** get value for key `i` */
TreeMap.apply(integer i)
You cannot do this with C
structs without essentially re-implementing subclass polymorphism as a design pattern.
Is it possible to use objects the old-fashioned-way and still consider it as functional programming?
It's not an all-or-nothing game. You can start with a classical oop-language (with mutable state and all that), which supports the functional programming paradigm to some degree. You can then look at your application, and isolate those aspects of it that require more precise control over the side effects. You have to decide which side effects matter, and which are less critical. Then you can express the really critical parts using the somewhat stricter approach with pure functions (pure in the sense: as pure as you need them to be, i.e. not performing any critical side-effects without declaring it explicitly in their signature). The result would be a mix of classical OOP and FP in one application.
Writing programs using pure functions can be thought of as a construction of a proof in a somewhat primitive logic. It's nice if you can do it when you need it (using a stricter approach with pure functions), but it can also be nice if you can omit it when you don't need it (using the usual approach with messy side-effecty functions).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With