Copy-on-write changes data by returning a modified copy instead of altering the existing value. This preserves purity and makes value objects safer to compose. section 4.5
Immutable money operations
A Money value object can freeze its properties and have methods such as plus, minus, round, and asNegative return new Money objects. Thus, USD(3).plus(USD(7)) produces a separate USD(10), while the original values remain unchanged. section 4.5
Copy-on-write is useful when:
- Value objects should behave immutably and avoid mutation-related bugs. section 4.5
- Nested object updates should remain composable; lenses can target a property or path while handling copying automatically. section 4.5
Listing 4.13 Details of the Money value object
const BTC = 'B|';
const Money = curry((currency, amount) =>
compose( #1
Object.seal,
Object.freeze
)(Object.assign(Object.create(null), #2
{
amount,
currency,
equals: other => currency === other.currency &&
amount === other.amount,
round: (precision = 2) =>
Money(currency, precisionRound(amount, precision)),
minus: m => Money(currency, amount - m.amount),
plus: m => Money(currency, amount + m.amount),
times: m => Money(currency, amount * m.amount),
compareTo: other => amount - other.amount,
asNegative: () => Money(currency, amount * -1),
valueOf: () => precisionRound(amount, 2), #3
toString: () => `${currency}${amount}`
}
))
);
// Zero
Money.zero = (currency = BTC) => Money(currency, 0); #4
// Static helper functions
Money.sum = (m1, m2) => m1.add(m2);
Money.subtract = (m1, m2) => m1.minus(m2);
Money.multiply = (m1, m2) => m1.times(m2);
function precisionRound(number, precision) {
const factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}
Inspect a Money implementation that combines frozen, sealed objects with methods using copy-on-write semantics. section 4.5




