Summary
An effect is a consequence of something happening in our program. Some effects are predictable as they’re consciously implemented. Other effects are out of reach and not controllable by the developer as they depend on outside factors. There are already several papers and research going on about “effect systems”.
If we want to truly respect the symmetries of the system, we need to rethink the situation. A static effect system would be something akin to Rust’s borrow checker but for effects. This would mean making sure that all effects are annotated properly.
There are Two Type Systems - the regular type system that we’re all used to and the effect system. An effect system is still its own form of type system. If you can’t prove that some function doesn’n’T have a side effect, that’s an error.
An effect has two properties: the subject and its lifetime. The subject is what was affected by the effect, whereas the lifetime is the range of the effect. All effects must be explicitly annotated (this ensures that the developer is aware that such effects take place) An effect is an effect, and all effects must have the same name.
In the case of I/O, the io effect is simply an alias for mut: std::io::OutputHandle deep within the standard library. The read_guess function itself does not trigger any side effects. Such a function can be considered pure. The effect system can prove that certain functions can be rewritten into a “pure’ format.
The rule is as follows: an effect will not be propagated if its lifetime is smaller or equal to the lifetime of the target. Let’s say we create a global variable (gasp) and try to mutate it from our return_5() function:let mut a = 3; // This is a globalvariable that lives for the duration of the program.
It's quite amazing how much tooling can be built around an effect system like this. Such a system also solves one of Rust’s issues, which is the lack of safety features. The system still needs to be tried in the real world to see if it functions as intended.