const fn = (T) => {
helper(T)
console.log(T)
}
class Component extends ... {
constructor(settings, model) {
super(this)
this.model = model
this.settings = settings
}
render() {
if (!settings.valid) { return }
}
}
class Model extends ... {
constructor(settings, user) { }
get item() {
if (settings.hasAccess(user)) {
return this.store('something')
}
}
}
S
B
B
B
B
S
S
S
B
S
S
B
B
B
B
S
S
S
B
S
B
S
Convoluted shared state
...in objects over time
The ”what changed problem”
Object observing is odd (change records)
Dirty flags are nasty (coupling)
Avoiding the "Many Mutators"-Problem
Time
State is value(s) over time (complected)
Initialisation
Mutation
Reassignment
Unsetting
Array.filter, Array.slice...
Array.sort, Array.push...
...people think in state and mutations
const THRESHOLD = 13
// 💣 THRESHOLD = 9
const CONFIG = {
threshold: 13,
api: 'v2'
}
// ⚠️ CONFIG.threshold = 2
const items = Object.assign(
{},
{ title: 'Buy milk', done: false }
{ title: 'Chocolate', done: true }
)
const items = { ...item1, ...item2 }
let a = { x: 1 }
let b = Object.assign({}, a)
console.log(b.x === a.x)
//true
const b = { ...a }
#fancyness
Closure
Scala
JavaScript
Java
#any
Haskell
let cars = ['VW', 'Scoda'];
let something = cars.push('Fiat');
something === 3;
cars.length === 3;
The mutation game
Array.prototype.immutable = (item) => {
let copy = this.slice(0);
copy.push(item);
return copy;
};
let drinks = ['Beer', 'Mate'];
let moreDrinks = drinks.immutable('Water');
(moreDrinks === drinks) === false;
New shiny things
Referential intransparent
Referential transparency
A
C
X
D
let list2 = list1.immutableSet(1, "E")
A
C
X
D
let list1 =
let list1 =
let list2 =
A
E
Data structure
4
2
1
1
2
3
3
2
Standard Trie
4,2,1,2
4,1,3
4,2
bar
00 01 10 11
Bitmapped Vector Trie
00 01 10 11
ba
bad
00 01 10 11
bb
00 01 10 11
1110 = bb
001010 = ba
00 01 10 11
00 01 10 11
00 01 10 11
00 01 10 11
"Bathrobe"
"Tobi"
42
dag.get("Tobi")
dag.hash("Tobi") === 001011
dag.set("Bathrobe") // 000100
dag.hash([1,2,3]) === 32-Bit Number!
hash(thing) = ?
Stuctural Sharing
Initial DAG
Copied node
Inserted
Shared
Garbage
(maybe) collected
00 01 10 11
00 01 10 11
00 01 10 11
00 01 10 11
"Company"
"Tobi"
42
00 01 10 11
00 01 10 11
00 01 10 11
"💣"
💣
💣
hash("GmbH") =
hash("💣") =
11 10 11 11
11 10 11 11
01 11 10
11 01 11
"GmbH"
00 01 10 11
O(1) * | O(log n) | O(n) |
---|---|---|
append | concat | |
first | insert | |
last | ||
nth | ||
update |
* O( log32 n): n being length of vector being at
most MAX_INTEGER makes it ~7
Mutable
Immutable
let model = {
name: 'Tobias',
age: 19,
height: 203
};
view(model).render();
model.age = 20;
// 1. Manually
view.render();
// 2. Eventing
model.change(view.render);
// 3. Setters as reach-in
view.setModel('age', 19);
let model = Immutable.Map({
name: 'Tobias',
age: 19,
height: 203
});
view(model).render();
modelWithNewAge = model.set('age', 19);
// Reference equality
(modelWithNewAge === model) === false;
model.get('name') === modelWithNewAge.get('name');
model.get('age') !== modelWithNewAge.get('age');
// Re-render with early exit in equality check
view(modelWithNewAge).render();
let presenter = Immutable.Map({
personal: Immutable.Map({
name: 'Tobias',
age: 19,
height: 203,
},
address: Immutable.Map({
city: 'Rastede',
zip: 20180
});
});
let relocatedPresenter = presenter
.setIn(
['address', 'city'], 'Berlin'
).setIn(
['address', 'zip'], 10437
);
relocatedPresenter.get('address') === presenter.get('address') // false
relocatedPresenter.get('personal') === presenter.get('personal') // true
No {shallow, deep} Equals
Complex & expensive
Memoization
No serialization with e.g. O(n)
Abstract at right place
Data Structure level not with model
List, Stack, Map, OrderedMap, Set,
OrderedSet and Record
Bridge into ClosureScript's data structures
Reactive & immutable
Immutable data structures with native JS
APIs
Cursors/pointers to watch immutable
data structures
💕 React, PReact, Inferno et al. 💕
Rigorous
One-off & Communicates
Performant
Structural Sharing
No accidental re-renderings
Integrates with CQRS
Event log (redux or even API)
Replay state at any time
Another API & Paradigm
Learning curve
Lock-in & integration friction
Development & Debugging
Non-native to JS
.toJS | log OR response | fromJS
Communication
Align all those developers