Let's forget what functional programming is for the moment. And just think about computations in general.
Let's say I have 3 things that I need to maintain state for. Let's call them "Thing 1", " Thing 2", and "Thing 3". And let's say to update the state of "Thing 3" needs an up to date state for "Thing 1" and "Thing 2". And to update the state of " Thing 2" requires an up to date state of "Thing 1".
So we develop the ranks:
"Thing 3": rank 3
"Thing 2": rank 2
"Thing 1": rank 1
Once one changes its state, we mark dependent things dirty, and update them ordered by their rank.
What is interesting is that there is no requirement what so ever that "Thing 1" to "Thing 3" have their state updated functionally. Imperative updates are fine.
The only problem with an imperative update in the case of sodium is if we keep a reference to the state beyond the end of the transaction.
Now Java's type system can not protect us from keeping a reference beyond the end of the transaction. However Rust's type system can! Rust can disallow
\a -> (a,a) for some types
a, making mutable updates safe.
Welcome to the intersection of functional and imperative.
Java may not be able to provide a compile time error on misuse. But a runtime error can still be developed. (Immutable projections that invalidate themselves beyond the end of an transaction.)
What we end up with is the performance of imperative programming with the compossibility and safety of functional programing.
This is not something I'm going to pursue any time soon. Its just an idea that has been haunting me for some time.