How to manage state to loosen coupling in PL design?

Viewed 15

Shared state creates lots of problems in software development, including making the program harder to restructure, test and maintain, increases the complexity of the program and changes do one part of the program affect others. It also makes multithreading harder, as there is need for synchronization. The underlying issue of shared state is that it tightens the coupling between the various entities of a program (procedures, threads, modules and so on), leading to the issues described above. My goal, from a pl designer's perspective is to create a pl that encourages (or forces) loose coupling (and ideally high cohesion) on the software written in it.

An attempt to solve this problem was made by structured programming. The guideline was to pass all state through the call stack (as function parameters) and to avoid global variables. I've read that this was proposed by Dijkstra by I have been unable to find more on that. More often than not however, this is not enforced, and one could pass references to a mutable resource.

Most functional languages aim to reduce side effects. Some examples from Wikipedia's page on side effects are: modifying a non-local variable, modifying a static local variable, modifying a mutable argument passed by reference. From that we can see that many side effects involve modifying shared state (and therefore tightening intercomponent coupling). In their reduction of side effects, most functional languages don't face the same issues as imperative ones, however side effects can be very useful as it has been explained.

OOP also attempts to tackle this issue. Polymorphism, data hiding and the focus on interfaces rather than implementation, helps decouple many parts of a program. State (variables) sits behind object interfaces and methods. A question that I've seen brought up is, if many objects communicate by passing messages (by calling the methods of each other), then the state encapsulated in an object is being accessed, just indirectly. If many objects are accessing (read/write) another object's state through its public interface, isn't that shared state with extra steps? It's an improvement, as this segragation from the outside world ensures the validity of that state and aids in the creation of interfaces, but it looks like shared state nonetheless. And of course there is the Singleton Object pattern, which looks an awful lot like a global variable with complications.

The realization of the problems tight coupling poses came early and is widespread, though not always in the same context or name. Go's don't communicate by sharing memory; share memory by communicating seems to be just another instance of that. Rust's ownership rules enable the compiler to enforce this.

There are the three main approaches to this issue that I'm aware of, and modern languages seem to utilize elements of all three. The main question is: having seen these approaches how could one try to solve the shared state (tight coupling) problem (in the context of pl design) with an imperative language? Are you aware of other proposed solutions? Could modifying and combining any of the above yield a suitable answer? I must note that although functional languages have kind of solved this, they are limited in their usability and usefulness (continually getting better of course), but I firmly believe an imperative solution would be ideal, due to the combination of ease of use and familiarity of concepts, and solving the problem of course. Discussion is welcome. Thank you.

0 Answers
Related