Created
December 9, 2014 14:01
-
-
Save plexus/42c6c9c63212182ee440 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# How to update values on immutable objects? | |
class Foo | |
def initialize(attrs) | |
@x = attrs.fetch(:x) | |
@y = attrs.fetch(:y) | |
freeze | |
end | |
end | |
foo = Foo.new(x: 5, y: 7) | |
# Option 0 | |
# Use x=9. Would be great but doesn't work in Ruby, it will always | |
# return it's argument so you can chain assignments | |
# Option 1 | |
class Foo | |
attr_reader :x, :y | |
def set_x(x) | |
self.class.new(x: x, y: y) | |
end | |
end | |
foo.set_x(9) # => #<Foo:0x007fbe1e7acc48 @x=9, @y=7> | |
foo # => #<Foo:0x007fbe1e7acd60 @x=5, @y=7> | |
# Option 2 | |
Undefined = Object.new | |
def Undefined.inspect ; 'Undefined' ; end | |
class Foo | |
def x(x = Undefined) | |
if x == Undefined | |
@x | |
else | |
self.class.new(x: x, y: @y) | |
end | |
end | |
end | |
foo.x(9) # => #<Foo:0x007fbe1e7ac4c8 @x=9, @y=7> | |
foo # => #<Foo:0x007fbe1e7acd60 @x=5, @y=7> | |
# Option 3 | |
# Same as #1, but with_x, apparently common in Scala/Java | |
# Option 4 | |
# Anima style, use explicit "update" function | |
require 'anima' | |
class Foo | |
include Anima.new(:x, :y) | |
include Anima::Update | |
end | |
foo.update(x: 9) # => #<Foo x=9 y=7> | |
foo # => #<Foo x=5 y=7> | |
# Option 5 | |
# ... | |
# Any other ideas? |
Great to get so many replies on this! It seems some people also name their update
/ copy
/ with
method new
. I've seen this and think I might have actually used it at some point, although I'm not a fan because it's different enough from the class method new to cause confusion.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Option #4 is common in plain Scala where it's called copy. Probably for the reason @moonglum stated.
All those options will be a pain with nested, immutable data structures, though. At that point lenses will come in handy. I'm not aware of a library for that in Ruby, though. You can probably do something more convenient with Ruby meta magic anyway, though. I'd think something like this:
As opposed to