In programming languages, side effects refer to any change in state that occurs when calling a function other than just returning a value. Common examples include modifying a global variable, mutating an object property, or performing I/O like console logging, file access, or network requests. These effects make reasoning about and testing code more difficult. Over the years, various methods have been proposed to bring side effects under tighter control through type systems.

One early attempt was using monads in functional languages like Haskell. Monads provide a way to sequence computations while isolating their effects. Different monad types represent different kinds of effects, like exception handling, I/O, or state changes. By parameterizing monad types over the return value, side effects can be strictly typed and contained. However, monadic programming has a steep learning curve and can lead to nested code that some find difficult to read.

Linear type systems take a different approach by treating objects with side effects as consumable resources. Aliasing and mutation are carefully controlled through uniqueness and ownership types that ensure objects are operated on in a linear fashion. Rust's borrow checker is a well-known example of applying linear types. But linearity introduces its own complex set of rules around pointers and borrowing, and remains somewhat limiting in expressiveness.

More recent work uses effect systems that explicitly label functions with the effects they may produce. These effect labels act like additional function parameters that can then be checked or inferred during type checking. Languages like Koka and Eff use algebraic effect types and handlers to model effects in a composable way. But adoption in mainstream languages has been limited due to the major changes required to type systems and runtimes.

While we still lack a definitive solution, adding information about effects into type systems appears a promising evolution. Taming effects will pave the way for safer and more reliable software development. As type systems grow more sophisticated at capturing real-world behavior in code, effects may one day become just another parameter to functions rather than a continued source of surprises.

None