Vesa Karvonen
Programs are about state. It can't be completely eliminated. It must be managed.
State changes over time so immutable state is an oxymoron. One can capture state at a point as an immutable value but that is not all.
One of the points of this talk is to argue that external shared global state is actually better than internal encapsulated local state.
There are no new "innovations" in this talk.
Most papers in computer science describe how their author learned what someone else already knew. — Peter Landin
State complects: Value and Identity and Time
Both identity and time are subtly complex!
Tracking identities often complicates algorithms e.g. React keys.
Change over time invalidates computations dependent on state.
Bugs, bugs, and more bugs!
let x = 1 // Creates mutable state
let y = 2
let sum = x + y // Takes snapshots of state
x = 3
sum // No longer valid
function foo() {
let x = 1 // Creates mutable state
bar(x) // Doesn't pass state - only value
x = 2 // Mutates state - not visible to `bar`
return x // Doesn't return state - only value
}
interface State<T> {
get(): T;
set(value: T): void;
}
class Atom {
constructor(value) {
this.value = value
}
get() {
return this.value
}
set(value) {
this.value = value
}
}
First-class: can pass as arguments and return as results
Program components can declare state as parameters
class Atom {
constructor(value) {
this.value = value
this.observers = []
}
get() { return this.value }
set(value) {
this.value = value
this.observers.forEach(observer => observer(value))
}
subscribe(observer) {
observer(this.get())
this.observers.push(observer)
}
}
Independence from time
class LensedAtom {
constructor({getter, setter}, source) {
this.getter = getter
this.setter = setter
this.source = source
}
get() {
return this.getter(this.source.get())
}
set(value) {
this.source.set(this.setter(value, this.source.get()))
}
}
Store state as a whole and slice elements of said state to components
class PairAtom {
constructor([lhs, rhs]) {
this.lhs = lhs
this.rhs = rhs
}
get() {
return [this.lhs.get(), this.rhs.get()]
}
set([lhs, rhs]) {
this.lhs.set(lhs)
this.rhs.set(rhs)
}
}
Transactionality
Independence from storage
Yes: Anyone who has access to a slice of state can mutate it.
Scope: A component that is given a slice of state as a parameter can only mutate that slice — not everything.
Intent: If you give mutable state to a component, the intention is that the component can mutate it.
Observe: Even if someone mutates the state, components can observe the state change and act accordingly.