0
Upcoming SlideShare
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Standard text messaging rates apply

# The disaster of mutable state

836

Published on

Explores the disastrous problems that mutable state and side effects entail, and discusses how to overcome them.

Explores the disastrous problems that mutable state and side effects entail, and discusses how to overcome them.

Published in: Software, Technology
7 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
Your message goes here
• Be the first to comment

Views
Total Views
836
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
24
0
Likes
7
Embeds 0
No embeds

No notes for slide

### Transcript

• 1. The disaster of mutable state
• 2. 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
• 3. 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
• 4. Benefits • Easier to reason about • Easier to test • Easier to compose & recombine • More modular • Safe caching • Share data with impunity • Thread-safe
• 5. 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)
• 6. 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
• 7. 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
• 8. 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
• 9. 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)
• 10. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
• 11. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
• 12. Composition pure style! • Give input, check output • output = foo(bar(baz(input)))
• 13. Composition pure style! • Put something inside another thing • output = foo(bar(baz(input)))
• 14. Testing pure style! • Give input, check output • output == foo(bar(baz(input))) Give it one of these …and we get this?
• 15. Composition mutable style
• 16. Composition mutable style
• 17. Composition mutable style
• 18. Composition mutable style
• 19. Composition mutable style
• 20. Composition mutable style
• 21. Composition mutable style
• 22. Composition mutable style
• 23. Composition mutable style
• 24. Composition mutable style
• 25. Composition mutable style
• 26. Composition mutable style
• 27. Composition mutable style
• 28. Composition mutable style
• 29. 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
• 30. 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.
• 31. Modularity (pure) What does this do? Elitist academic Ivory Tower genius
• 32. Modularity (pure) What does this do? Elitist academic Ivory Tower genius
• 33. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
• 34. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
• 35. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
• 36. Modularity (with side-effects) What does this do? Pragmatic real world coder who gets shit done
• 37. 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
• 38. “I’m not smart enough to use mutable state!” - Functional programmers
• 39. State, time & identity “But the real world is mutable!”
• 40. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation
• 41. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation => “bald” => “actor”
• 42. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupation => “bald” => “actor” ... in 2014
• 43. State, time & identity samuel_l_jackson.hairstyle samuel_l_jackson.occupatio n => “afro” => “student” 1960s:
• 44. State, time & identity “Samuel L Jackson” 1960 1970 1980 1990 2000 2010 H: “bald” O: “actor” H: “afro” O: “student” Identity
• 45. 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
• 46. Arguably OK identity class ToyRobot attr_accessor :facing, :pos end
• 47. Arguably OK identity • ToyRobot will hold many facing/position states over time • Robot’s identity is at least a meaningful concept
• 48. Totally wrong and broken identity class Position attr_accessor :x, :y end
• 49. 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?
• 50. 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
• 51. Better: separate the identity class ToyRobot attr_reader :facing, :pos end current_robots = { :r2d2 => ToyRobot.new ... :c3p0 => ... :dexter => ... :rdolivaw => ... }
• 52. Emphasis on transitions • No: “Take this robot and change it” • Yes: “Specify the transformation from one robot to another”
• 53. But this map is still mutable! • At least we have shunted the mutability out a layer! current_robots = { :r2d2 => ... } current_robots.each { |id, bot| current_robots[:id] = bot.update() }
• 54. One more level: immutable hashes • https://github.com/hamstergem/hamster current_robots = Hamster.hash( :r2d2 => ToyRobot.new ... ... ) current_robots.fold(Hamster.hash) { |next_robots, id, bot| next_robots.put(id, bot.update) }
• 55. One more level: immutable world class World attr_reader :current_robots def update # return updated world end end def whole_program(current_world) whole_program(current_world.update) end
• 56. Separating decisions from actions • Often side-effecting code mixes decisions with actions def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) send_email(email, content) else log(“[info] Couldn’t send email”) end end
• 57. Separating decisions from actions 1) Validity checking (pure) def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) send_email(email, content) else log(“[info] Couldn’t send email”) end end
• 58. Separating decisions from actions 2) Generate email content (pure) def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) send_email(email, content) else log(“[info] Couldn’t send email”) end end
• 59. Separating decisions from actions 3) Decide to send (pure), and act on it (I/O) def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) send_email(email, content) else log(“[info] Couldn’t send email”) end end
• 60. Separating decisions from actions 4) Decide to log the failure (pure), and do it (I/O) def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) send_email(email, content) else log(“[info] Couldn’t send email”) end end
• 61. Explicit decision class Decision; end class SendEmail < Decision attr_reader :email, :content end class Log < Decision attr_reader :message end class DoNothing < Decision; end
• 62. Pure version def send_welcome_email email, pwd if valid(email, pwd) content = create_content(email) SendEmail.new(email, content) else Log.new( “[info] Couldn’t send email”) end end
• 63. Party at the end of the world def run_pure # Return decisions [ ... ] end def interpret_decision d case d when Log puts d.message when SendEmail actually_send d.email, d.content when DoNothing end end
• 64. Big problems; huge wins 1. Mutable state causes immense harm to our software 2. Referential transparency and purity bring corresponding benefits 3. It’s not hard to start reaping the benefits