640 likes | 676 Views
Explores the disastrous problems that mutable state and side effects entail, and discusses how to overcome them.
E N D
The disaster of mutable state The disaster of mutable state
What’s the big deal 1. Referential transparency is super important 2. Effects and mutability do immense damage 3. How to write a pure core with a thin effectful crust What’s the big deal 1. Referential transparency is super important 2. Effects and mutability do immense damage 3. How to write a pure core with a thin effectful crust
Referential transparency • For the given inputs, we will always get the same outputs • Like a mathematical function • You can substitute an expression with its results Referential transparency • For the given inputs, we will always get the same outputs • Like a mathematical function • You can substitute an expression with its results
Benefits • Easier to reason about • Easier to test • Easier to compose & recombine • More modular • Safe caching • Share data with impunity • Thread-safe Benefits • Easier to reason about • Easier to test • Easier to compose & recombine • More modular • Safe caching • Share data with impunity • Thread-safe
Drawbacks? • Requires some discipline to maintain • If you break RT in one place, it ruins everything • Updating data requires copying data structures, which might be expensive (or not) Drawbacks? • Requires some discipline to maintain • If you break RT in one place, it ruins everything • Updating data requires copying data structures, which might be expensive (or not)
What’s off the menu? • Network/DB/File system I/O • Mutating state • Reading/observing state that can be mutated • Creating a mutable object • Reference equality • Time.now() • random() • Exceptions What’s off the menu? • Network/DB/File system I/O • Mutating state • Reading/observing state that can be mutated • Creating a mutable object • Reference equality • Time.now() • random() • Exceptions
Equational reasoning • Our starting point is no more complex than the final result, and can be replaced without changing the meaning • Order doesn’t matter 2 + (25 * 3) – 7 = 2 + 75 – 7 = 77 – 7 = 70 Equational reasoning • Our starting point is no more complex than the final result, and can be replaced without changing the meaning • Order doesn’t matter 2 + (25 * 3) – 7 = 2 + 75 – 7 = 77 – 7 = 70
Pure example def add(a,b) a + b end def mult(a,b) a * b end # Interchangeable # Evaluation order doesn’t matter add(4, mult(3,2)) add(4, 6) 10 Pure example def add(a,b) a + b end def mult(a,b) a * b end # Interchangeable # Evaluation order doesn’t matter add(4, mult(3,2)) add(4, 6) 10
Impure example mutavar = 0 def mult(num) mutavar *= num end def add(num) mutavar += num end # Cannot change order # Cannot substitute actions for results add(5) mult(2) add(-2) Impure example mutavar = 0 def mult(num) mutavar *= num end def add(num) mutavar += num end # Cannot change order # Cannot substitute actions for results add(5) mult(2) add(-2)
. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
. Composition pure style! • Put something inside another thing • output = foo(bar(baz(input)))
. Testing pure style! • Give input, check output • output == foo(bar(baz(input))) Give it one of these …and we get this?
. Composition mutable style • We need to fit every level of detail in our head! We can’t ignore anything. • Any level could fiddle with something that changes the whole • Non-modular • Not really “composition” in a true sense
. Testing mutable style! AKA “web of lies” MOCK – HANDLE WITH CARE MOCK – HANDLE WITH CARE If I say “Gerbil”, then you say “Party time!” And then you call my thing with a baked potato! The 3rd time I knock, then you put on a Darth Vader mask and breath heavily Let’s totally alter the fabric of space-time.
. Modularity (pure) What does this do? Elitist academic Ivory Tower genius
. Modularity (pure) What does this do? Elitist academic Ivory Tower genius
. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done Expected order 1) This 2) That 3) Depends 4) ??? 5) Touches here 6) Widdles the widget 7) Diddles the doobilacky Gets a bit hairy here Best we don’t modify this
. “I’m not smart enough to use mutable state!” - Functional programmers
. State, time & identity “But the real world is mutable!”
. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation
. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation => “bald” => “actor”
. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation => “bald” => “actor” ... in 2014
. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupatio n => “afro” => “student” 1960s:
. State, time & identity “Samuel L Jackson” 1960 1970 1980 1990 2000 2010 H: “bald” O: “actor” H: “afro” O: “student” Identity
. State, time & identity • Mutable state implies identity • This totally changes the nature of the object • Identities refer to different states over time • Each state is eternal and immutable
. Arguably OK identity class ToyRobot attr_accessor :facing, :pos end
. Arguably OK identity • ToyRobot will hold many facing/position states over time • Robot’s identity is at least a meaningful concept
. Totally wrong and broken identity class Position attr_accessor :x, :y end
. Totally wrong and broken identity • A position can change under your feet! • What can it possibly mean?? • What use is an identity that strings together different Position states over time?
. Consider… class Integer attr_accessor :value def plus(n); value += n.value; end end three = Integer.new 3 three.value = 4 three.plus(three) 8