7

I know that obviously every language has its own characteristics and implementations, but from a theoretical standing point, viewing OOP as an abstract programming paradigm, does it allows side effects? Does it change the program state?

Every object has its own state and an object can change its own state or another object's state. So, is this state the same with the program state? And thus, OOP is not stateless?

On the other hand, OOP allows for side effects (observable interactions between objects, modify global vars).

So OOP is stateful and allows side effects? Did I got it right?

slevin
  • 179
  • 1
  • 5
  • 1
    Possible duplicate of [If immutable objects are good, why do people keep creating mutable objects?](https://softwareengineering.stackexchange.com/questions/151733/if-immutable-objects-are-good-why-do-people-keep-creating-mutable-objects) – gnat Aug 10 '17 at 11:49
  • see also: [Origin of “a method should return a value or have side-effects, but not both”](https://softwareengineering.stackexchange.com/a/289952/31260) – gnat Aug 10 '17 at 11:51
  • 2
    Who or what gave you the idea that state is bad? – Martin Maat Aug 10 '17 at 12:50
  • 1
    @MartinMaat But I never said state is bad – slevin Aug 10 '17 at 13:29
  • @slevin No you did not. But why the question? It is code that is either stateful or stateless, the language or OOP just facilitates. The programmer makes the code either stateful or stateless. And what do you mean by the program state versus object state? It is a confusing question that led me to believe you heard some bad things about state in general. – Martin Maat Aug 10 '17 at 13:50
  • @MartinMaat I see. Well, I revisited basic standards and concepts and the Wikipeida categorization confused me because it looked like every programming paradigm should be just one thing or another. On the other hand, some paradigms better support one style because they were designed to do so, with statefulsness or statelesness in mind (eg imperative considered stateful, declarative stateless, FP stateless). – slevin Aug 10 '17 at 14:09
  • @MartinMaat Also the [wikipedia definition of the state](https://en.wikipedia.org/wiki/State_(computer_science)) made me question if there is a difference between "program state" (state of the whole program executed to do something) and "object state" (state of an object that does not influences the outcome of the whole program) – slevin Aug 10 '17 at 14:09
  • 3
    Q: "Does object-oriented programming allows side effects and state changes?" A: "A lot". – Machado Aug 10 '17 at 18:03
  • The way i think about it, a program can be procedural (static variables) or object oriented (data stored in objects), and simultaneously, it can be imperative (based on mutation and side effects) or functional (based on pure, reverentially transparent functions). When people refer to OO, they usually refer to OO imperative. – Phoenix Aug 12 '17 at 16:35

4 Answers4

10

There is no universal definition of OOP. It is therefore difficult to make a statement like “OOP is stateful”. There are both examples where OOP involves state and examples where OOP is used without any state. OOP tends to be paired with imperative programming, which certainly allows side effects and mutable state.

There is one line of thought that OOP is about encapsulation. OOP is not needed to organize the program state into smaller records/structs. But if we turn those records into objects and encapsulate this data behind a message-passing interface, we can disentangle the program state, leading to a more decoupled and modularized architecture.

That way the state is still there, but we can look at parts of the state (each object) in isolation. There won't be any outside interference. If outside users want to access or change the state, they will have to call a method that we control. It is now easier to reason about an object. Conversely, outside users only need to know about the public interface and not all internal details, which makes their life easier as well.

So one could say that OOP is a technique for managing program state more easily.

Using OOP for encapsulation like this lends itself well to larger software systems, at least in theory. This idea is not restricted to single object instances in a programming language. One could also view larger architectures as object-oriented, e.g. in a microservice architecture each individual microservice can be interpreted as an object.

In most OOP-ish programs this state management is not done cleanly. Any time you access a global variable or call a static function you are side-stepping the decoupling benefits of only communicating via method calls. This will come back to bite you if you write unit tests for an object – any data flow through static members is data flow you can't intercept, mock, and verify.

OOP is not the only way to manage state within a larger application. Most of these features like “encapsulation” are merely an example of the modular programming paradigm, but there's no clear line between modular and object-oriented programming. Instead of parcelling state into smaller chunks that send messages to each other, functional programming suggests making all state explicit and immutable. The program flow can then be interpreted as state transformations rather than state mutations.

amon
  • 132,749
  • 27
  • 279
  • 375
  • Thanks for the detailed answer. One thing. Can you elaborate a little more on the "state transformations rather than state mutations" ? What is the difference between state transformation and state mutation? Do you have any links? Thanks – slevin Aug 10 '17 at 18:58
  • 3
    @slevin With state mutation I mean that the state is changed: `process(state)`. Sometimes this state is hidden/implicit/global. With state transformation, a new state is created and the old state left unchanged: `newState = process(oldState)`. By making all state explicit, the process is completely characterized by its input and output, i.e. behaves like a pure mathematical function. There is no hidden state. This is easier to analyze, understand, and test. Functional programming prefers this explicitness, but it isn't perfect either: this focus on mathematical purity often gets in the way. – amon Aug 10 '17 at 19:52
  • 1
    Good answer. No universal definition of OOP, it is true, but going back to the first object oriented language (smalltalk), does serve to remind us of the original motivations behind the ideas. Lately I often hear about the "right" and "wrong" way to do OOP, to the detriment of the industry. – Frank Hileman Aug 10 '17 at 22:27
  • @FrankHileman: As far as I know, SIMULA 67 is older than Smalltalk. Also, I attended a course on programming languages which maintained that dynamic dispatch is what characterizes OO. Other features like encapsulation, state mutation and so on, are only found in particular flavours of object orientation. – Giorgio Aug 11 '17 at 09:52
  • @Giorgio Yes, OO was mostly discovered during the development of Simula II. But OOP as a concept was largely researched in the context of Smalltalk. There is no agreement what concepts characterize OOP, and dynamic dispatch can also be used for techniques that don't look OO. Some definitions I've seen include: modelling the real world (by Nygaard) (compare also DDD), message-passing (by Alan Kay), open recursion (by Pierce), SOLID, esp. dependency inversion (by Robert C. Martin), polymorphism+encapsulation+inheritance, or object=data+behaviour. See also: http://wiki.c2.com/?DefinitionsForOo – amon Aug 11 '17 at 10:20
  • 1
    Keep in mind that not all static members are bad. There are several use cases (Math functions being the most common example) that lend themselves very well to be implemented as static. You _can_ unit test static stuff, despite what most people say about them - albeit you need to take some care to implement only pure functions (as in, no side effects) as your static stuff. – T. Sar Aug 11 '17 at 11:20
  • @Giorgio it was a continual set of improvements to languages, definitely. But the term "object oriented" to my knowledge was first used for Smalltalk. At the time (yes I am that old) I did hear talk of objects, and object based programming -- not quite the same. – Frank Hileman Aug 11 '17 at 23:05
  • @T.Sar the word "static" is language specific -- I have no trouble understanding what you mean, but you might wish to use a different term. – Frank Hileman Aug 11 '17 at 23:17
  • @amon: "dynamic dispatch can also be used for techniques that don't look OO": Can you give an example? – Giorgio Aug 12 '17 at 07:02
  • 1/? @Giorgio Dynamic dispatch happens whenever function pointers are involved. One more interesting case is dynamically loaded libraries. Their relocation tables are quite similar to vtables in C++-style OOP. The ABI is known at compile time, but the concrete libraries and call targets are only resolved at runtime. There might be multiple libraries offering the same interface. This polymorphism can sometimes be used to implement plugin systems. – amon Aug 12 '17 at 18:23
  • 2/? Despite these strong similarities to objects, I don't think dynamic libraries are OOP, primarily because libraries are not a first-class concept in any language I know (except perhaps with something like POSIX `dlopen()`) and because only one DL “instance” can be loaded into each address space (a problem Java 9 modules and similar technologies seem to address). – amon Aug 12 '17 at 18:24
  • 3/3 I'd also like to point out Haskell typeclasses as an example for non-OOP dynamic dispatch. These classes define an interface that is used for dynamic dispatch, but the interfaces are type constraints, not types themselves. The core language does not have objects and the tables for dynamic dispatch are tracked separately from values. You can therefore have polymorphic functions (like a `print` function working with any `Show`-able type) but not polymorphic values (like a heterogenous list that can contain any `Show`-able value). – amon Aug 12 '17 at 18:25
  • "Haskell typeclasses as an example for non-OOP dynamic dispatch": Is this really an example of dynamic dispatch? The implementation of each function is chosen at compile time, or am I missing something? – Giorgio Aug 12 '17 at 18:37
  • @Giorgio At first Haskell polymorphism appears similar to C++ templates, but as an implementation detail each generic function is only compiled once – more like Java generics. This works via type erasure: a generic function is oblivious to the concrete types for type parameters and only interacts with them through the methods supplied by the typeclass. The typeclass instance (= vtable) is effectively passed as an implicit parameter. E.g. within a function `myMax :: Cmp a => a -> a -> a` `myMax x y = if (x > y) then x else y` the call to `>` is dynamically dispatched through the Cmp typeclass. – amon Aug 12 '17 at 19:05
  • It turns I'm wrong about “as an implementation detail” – it is possible to write generic functions where the exact type of all type parameters is not statically known, therefore type erasure + dynamic dispatch may be the only options to compile such functions. Here is a subtle example where parameter `a` through recursion takes on types `Int`, `[Int]`, `[[Int]]` and so on up to an arbitrary runtime-dependent depth: https://stackoverflow.com/a/10535629 – amon Aug 12 '17 at 19:18
  • @amon: Interestingly, William Cook argues that Microsoft's COM is the mainstream technology that is closest to Alan Kay's vision of OO, precisely because everything is encapsulated behind an interface, and every message is dispatched dynamically. Also, I would argue that definitions of OO are much closer than people realize. I.e. Open Recursion is basically the Type System feature that makes Messaging possible, and if everything is a Message Send, then everything is necessarily encapsulated and polymorphic (and inheritance is just differential code-reuse and a good idea independent of OO). – Jörg W Mittag Aug 13 '17 at 20:31
  • William Cook did some research on how the term "OO" is *actually* used in the real world (as opposed to how it is defined by textbooks), and he found that the single thing that all languages, libraries, frameworks, patterns, etc. that are commonly characterized as OO have in common and the one thing that is lacking from all those that are commonly characterized as "non-OO", *is* dynamic dispatch, which is an implementation strategy for messaging, the prerequisite for which is open recursion, and which implies encapsulation and polymorphism. So, really, all those definitions actually agree. – Jörg W Mittag Aug 13 '17 at 20:36
  • "we can look at parts of the state (each object) in isolation." – Alan Kay knew the people who were in the process of inventing what would later become the ARPANet (and then the Internet), and his vision of OO was heavily influenced by them. He envisioned each object as its own computer, with its own state (its instance variables, analogous to computer's RAM) that communicate with each other by sending messages (just like computers on the Internet). And just like on the Internet, you cannot access another computer's RAM, and you have no idea what that computer does with your message. It might – Jörg W Mittag Aug 13 '17 at 20:41
  • respond to it with a piece of pre-canned data (a "getter"), it might compute something and send that back (a "method"), it might hand it off to someone else to compute, it might employ the help of multiple other computers, etc. All you can observe is the response (that's encapsulation). *How* to respond is completely under the computer's discretion (that's polymorphism). He basically said that if messaging is good enough to build a network that spans the entire world, then it surely also be good enough to build a network of objects inside a program. – Jörg W Mittag Aug 13 '17 at 20:45
4

Here's a somewhat heterodox but, I (biasedly) think, interesting perspective.

Originally, my opinion was that state and object identity were not integral parts of OO "in theory", though they are ubiquitous in practice. It's quite easy (if unusual) to avoid mutable state entirely in an OO language like Java (modulo wanting to use standard libraries...) For example, Abadi and Cardelli had both mutable and immutable versions of their ς-calculus which was intended to be for OO what the λ-calculus is for FP. Suffice it to say, neither it nor any other "object calculus" has actually managed to claim such a role.

There's basically only one other "calculus" that has gained significance even approaching the λ-calculus' and that's Milner's π-calculus which was designed for reasoning about concurrent systems. My views changed after writing a decent amount of code in a π-calculus style, and particularly when discovering the blue and deep blue calculi which note that code written in the π-calculus tends to look and feel like working in continuation-passing style and endeavors to provide a "direct style" variation of the π-calculus. The result is rather like a concurrent OO language (and one that can smoothly capture the ς-calculus no less). Similarly, even writing code in the π-calculus tends to produce patterns that are very reminiscent of OO-style objects.

This perspective provides a firm footing for many, but not all, aspects of OO languages, and concurrency and OO have been interrelated in a variety of ways (actor model, active objects, the discrete event simulations of Simula, message passing) throughout the history of OO. Of course, most modern OO languages don't emphasize concurrency. Indeed, the vision of OO this perspective suggests looks a lot more like Erlang than Java. Nevertheless, this perspective does entail that mutable state and object identity are inherent. While within a "process" we may not have mutable state, as in Erlang where each process' body is (mostly) purely functional, it's trivial to model mutable state as a process. Similarly, while the π-calculus doesn't have anything like reference equality and it's non-trivial to model it, it's nevertheless clear that two processes are distinct even if they have the exact same definition. (In Erlang/actor terms, they have different "mailboxes".)

Derek Elkins left SE
  • 6,591
  • 2
  • 13
  • 21
3

I believe that Object-Oriented does allow side effects and state changes but well-designed object systems do it in one relatively small, well-delimited bubble at a time. Actor-based platforms are a good example of this principle followed strictly.

If you look at Alan Kay's account of the beginnings of Smalltalk (the language that introduced the term object-oriented) and early OO languages, whether to ultimately change state or not didn't even seem to be a question back then. It was implied that something had to be mutable in order for a system to run, but what really mattered was how and whether the calling object should be aware of any of it. Namely, the big idea was that objects had an internal memory, one that couldn't be modified from the outside with direct fine grained assignments, but could only be transitioned by calling methods reflecting higher-level behaviors of the object.

  1. Everything is an object
  2. Objects communicate by sending and receiving messages (in terms of objects)
  3. Objects have their own memory (in terms of objects)

[...]

The last thing you wanted any programmer to do is mess with internal state even if presented figuratively. Instead, the objects should be presented as sites of higher level behaviors more appropriate for use as dynamic components.

[...]

It is unfortunate that much of what is called "object-oriented programming" today is simply old style programming with fancier constructs. Many programs are loaded with "assignment*style" operations now done by more expensive attached procedures.

[...]

However, doing encapsulation right is a commitment not just to abstraction of state, but to eliminate state oriented metaphors from programming.

(In The Early History of Smalltalk, p. 19, 25)

guillaume31
  • 8,358
  • 22
  • 33
  • Very good research! My own interpretation of those comments was that the state machine, and system invariants, are all encapsulated. However, nowhere is it implied in your quotes that objects must have mutable state. I have always assumed that traditional functional style programming, including pure functions, would often exist at the end of call chains. For example, a square root function needs no mutable state, and it may call other pure functions within. The type of "old style programming" he refers to has to do with the over use of mutable state -- still a problem today. – Frank Hileman Aug 11 '17 at 23:14
  • Thank you. I believe he refers to something more specific though - mutable state by use of direct assignment statements. This is your setters in nowadays' OO. In contrast, nowhere does he mention that mutating state indirectly through high-level method calls is problematic. Actually, the words *mutable* or *mutability* never appear in the paper. – guillaume31 Aug 12 '17 at 00:36
  • you are right: "The last thing you wanted any programmer to do is mess with internal state even if presented figuratively. Instead, the objects should be presented as sites of higher level behaviors more appropriate for use as dynamic components." It is all about encapsulation and semantics in method names; using objects without knowing about internal details to achieve higher levels of abstraction. – Frank Hileman Aug 13 '17 at 23:05
-5

Most OOP languages allow you to create static classes, which are basically stateless objects. If that were all it would be pretty sad, fortunately you can also make classes that serve as templates for creating instances, in other words stateful objects. For any less than utterly trivial application you will need the latter kind.

State is not bad, without it IT would be limited to some very simple control functions.

Martin Maat
  • 18,218
  • 3
  • 30
  • 57
  • 2
    There are entire programming languages that are almost entirely without mutable state. – Nick Keighley Aug 10 '17 at 13:02
  • @NickKeighley They don't allow you to modify an objet, but you just assign the reference of the new one in place of the old one. The new one being a modified version of the old one. If you think like a C dev, consider that you're using pointer and they allow you only to modify where the pointer point and not the content. In the end both can achieve the same result. – Walfrat Aug 10 '17 at 14:06
  • Your first sentence is incorrect: static classes may have state, and often do. e.g. a Math class might have a static property PI, which is a state. However, the state is _usually_ immutable. In Java at least, a static class can have modifiable state, though that is usually a bad idea. – user949300 Aug 10 '17 at 14:32
  • @user949300 you are conflating static objects with static classes. You are right about static classes often having members – Caleth Aug 10 '17 at 14:36
  • @Caleth - You are correct, I quickly edited my comment after realizing my object vs. class mistake. Should think more before typing... – user949300 Aug 10 '17 at 14:37
  • @user949300 In the OO context a static class is stateless. Sure you can have data members but they are not bound to an object instance, thus there will never be a stateful object, it is just a namespace with some variables. This makes the behavior of any method of that class stateless, there is no this/self/me. And constants are not state, state can change. – Martin Maat Aug 10 '17 at 15:11
  • I've never seen static classes in any OOP system except for C#. In fact, there are OOP systems without any kind of “static” data whatsoever (e.g. Smalltalk). I'd therefore argue that staticness is completely orthogonal to any discussion about OOP concepts. – amon Aug 10 '17 at 17:19
  • @amon C++ has static classes, Delphi has them. But this is besides the point, I was addressing state as an essential element of OOP, claiming OOP would ve pretty pointless without it. Which is basically what you are saying. It seems to me we are on the same page. – Martin Maat Aug 10 '17 at 20:21
  • 1
    I think what you mean are *immutable* classes, not *static* classes. – Philipp Aug 11 '17 at 09:06
  • "Static" is just another name for _Global_, and has nothing to do with the ability of a given object to store state. A static class is no different from a bunch of global methods and global variables at disposal of the code. Saying that "in the OO context a static class is stateless" is nonsense - OO doesn't even _define_ the concept of Static or Global. – T. Sar Aug 11 '17 at 11:28
  • @T.Sar: This being blown out of context. The OP writes: "Every object has its own state" and goes on to call OO stateful. I stay in that line of thinking pointing out that if you want to go stateless (regarding *behavior*), you can use a static class which has no data of its own. From an OO point of view that makes it stateless. I also pointed out a static class is just a namespace. And then some robots go "static is not the same as stateless". That is not the point, we are talking OO regarding state. – Martin Maat Aug 11 '17 at 12:23
  • Yes, and you mixed up a concept that has nothing to do with OO. _YOU_ said that static classes are basically _stateless objects_. This _is wrong_. Don't complain if people donwvote you because you mixed up concepts that have nothing to do with each other. – T. Sar Aug 11 '17 at 13:06