In functional programming, purity immutability is one of the concepts that people usually emphasize on. By purity, I understand as enforcing values in the program to be immutable, at least as a specification for the language user (this includes languages such as Koka-lang where as a backend optimization their values might get mutated once it is statically knowable that the reference is unique)
However, as I observe, in these recent years, a new trend (not that the idea is new, but it is the first time the idea gains significant attention from the public outside of academic I suppose) that I would conveniently label as mutable value semantics (MVS for short), as borrowed from Native Implementation of Mutable Value Semantics has occurred. The most noticeable events would be the rising of Rust, with its ownership and borrowing system. Also, Hylo | The Hylo Programming Language (hylo-lang.org) also catches my attention.
To be self-contained, here is what I mean by my umbrella term MVS:
When calling functions on variables, the compiler does things more intelligently and tracks the change of state of the variables being used, instead of being overly optimistic like Haskell where variables are supposed to be unchanged, thus purity has to be enforced, or being overly pessimistic like usual imperative languages where statically analyzing the states is deemed infeasible in general.
Here is a simplest example, in Rust,
fn use_it_up(x:String) {
println!("I consume the {:?} now, you cannot use it any more!", x)
}
fn main() {
let x = "123".to_string();
use_it_up(x);
use_it_up(x); // again
// ^
//compiler would decide the x here
//is no longer usable, and complains
}
This code results in an error saying that I am attempting to use a moved value. (Well strictly speaking it is not mutating values so my usage of the term MVS is bad but I emphasize on the fact that the state of the used variables in the expression is semantically changed after the function call, i.e., in this case, the value of x
becomes moved).
In other more complex examples, the compiler might track whether the variables are getting referenced (borrow checker in Rust), or whether the variables will be put back, like inout
.
If one has to get into a holy war between programming paradigms, I might say this feels like a comeback for imperative programming. But eventually, FP or IP, in terms of semantics (as opposed to syntax), I personally only care about how I communicate with the compiler, the library and the user. And MVS feels a much more nuanced way to do so compared to both worlds of the past (just assume it is impure mutability or just enforce purity immutability).
In fact, this line of trend totally moves me out of the purity immutability camp (never in tbh). It is probably better, instead of saying we should ban mutation because it causes all sorts of problems, to say that we should communicate our intention as clearly as possible to the compiler, the caller, and the callee so that when I mutate or want to keep a reference to a value, they can be noticed, so that they can leverage their tools to optimize, verify and modularize.
But in Haskell, the fundamental of it seems to prevent such addition? I want to know what the Haskell community thinks of these kinds of language features(?), whether it is actually good or bad compared to alternatives, its desirability and feasibility in Haskell.