|
| 1 | ++++ |
| 2 | +title = "Immutability in Phel: Why Your Data Should Never Change" |
| 3 | +aliases = [ "/blog/immutability" ] |
| 4 | ++++ |
| 5 | + |
| 6 | +Phel lives and breathes persistent data structures. Instead of rewriting values in place, every operation hands you a fresh value that still shares most of the old data. It is the easiest way to keep code honest in a functional world. |
| 7 | + |
| 8 | +If you're coming from PHP's mutable arrays and objects, that default can feel strange at first. Stick with it: the pay-off is code that is easier to reason about, simpler to test, and naturally safe when things happen in parallel. |
| 9 | + |
| 10 | +## Goodbye in-place updates |
| 11 | + |
| 12 | +[Vectors](/documentation/data-structures/#vectors), [maps](/documentation/data-structures/#maps), [sets](/documentation/data-structures/#sets), [lists](/documentation/data-structures/#lists), and [structs](/documentation/data-structures/#structs) in Phel never mutate. Helpers such as `push` and `put` hand you the updated collection while the original stays exactly the same. |
| 13 | + |
| 14 | +```phel |
| 15 | +(def groceries [:milk :bread]) |
| 16 | +(def extended (push groceries :apples)) |
| 17 | +
|
| 18 | +groceries |
| 19 | +=> [:milk :bread] |
| 20 | +
|
| 21 | +extended |
| 22 | +=> [:milk :bread :apples] |
| 23 | +``` |
| 24 | + |
| 25 | +Because `groceries` never changes, any function that already received it can keep using it without worrying about sneaky side effects. Maps behave the same way: |
| 26 | + |
| 27 | +```phel |
| 28 | +(def customer {:id 42 :name "Ada"}) |
| 29 | +(let [with-email (put customer :email "[email protected]")] |
| 30 | + [customer with-email]) |
| 31 | +=> [{:id 42 :name "Ada"} |
| 32 | + {:id 42 :name "Ada" :email "[email protected]"}] |
| 33 | +``` |
| 34 | + |
| 35 | +`put` returns a new map that shares everything it can with the original. The copy is cheap thanks to structural sharing, Phel only allocates the path that actually changed. |
| 36 | + |
| 37 | +## Benefits of data that never changes |
| 38 | + |
| 39 | +- **Predictable functions**: With immutable inputs, the only variable is the arguments themselves. This guarantees referential transparency and eliminates hidden, hard-to-trace bugs. |
| 40 | +- **Stress-free tests**: Testing pure functions is effortless, just pass in data, check the result, and forget about mocking or side effects. |
| 41 | +- **Simpler debugging**: Log it once, and it stays true, no sneaky mutations hiding under your traces. |
| 42 | +- **Effortless concurrency**: Pass the same data between async jobs without race conditions or surprises. |
| 43 | + |
| 44 | +## Transforming data in steps |
| 45 | + |
| 46 | +Immutability pairs nicely with Phel's pipeline-friendly tools. Each step receives a value, returns a fresh one, and the original remains available for whatever comes next. |
| 47 | + |
| 48 | +```phel |
| 49 | +(def scores [10 18 21 7]) |
| 50 | +
|
| 51 | +(->> scores |
| 52 | + (filter |(>= $ 15)) |
| 53 | + (map |(- $ 10)) |
| 54 | + (reduce + 0)) |
| 55 | +=> 19 |
| 56 | +
|
| 57 | +scores |
| 58 | +=> [10 18 21 7] |
| 59 | +``` |
| 60 | + |
| 61 | +The vector `scores` is still the same after the reduction, ready to reuse later. That makes it trivial to layer different views over the same base data. |
| 62 | + |
| 63 | +## Managing change at the edges |
| 64 | + |
| 65 | +Real programs still need to talk to the outside world; databases, APIs, the filesystem. Immutability doesn’t stop that; it just asks you to keep those side effects in their own little corner. |
| 66 | + |
| 67 | +Do your updates at clear entry points, turn any external data into immutable Phel values, and let the rest of your code run safely on pure data. When you need a new version, use helpers like `put-in`, `unset`, or `push`, and pass the new value forward instead of mutating it. |
| 68 | + |
| 69 | +Once you stop changing data in place, life gets simpler: there’s the value you got, and the value you return. **That's it**. Everything else becomes easier to trust, and that’s why, in Phel, your data never changes. |
0 commit comments