Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active June 18, 2018 00:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/af12cd54b5974aec3643d0e3312bf8e0 to your computer and use it in GitHub Desktop.
Save JoshCheek/af12cd54b5974aec3643d0e3312bf8e0 to your computer and use it in GitHub Desktop.
Contemplating immutability: Fixnum vs Bignum
RUBY_VERSION # => "2.5.0"
class Integer
def add! n
# don't do this in real code, it's a timebomb full of segfault
require 'fiddle'
digits = Fiddle::Pointer.new object_id*2+16
digits[0, 8] = [digits[0, 8].unpack('Q')[0]+n].pack('Q')
end
end
original = 10**25
# With a Bignum, the value is stored in memory, so we can mutate its value.
# We say it's immutable b/c we're not given methods that can do this,
# and also because all Bignums are frozen, IOW, we choose to not modify it
num = original
num # => 10000000000000000000000000
num.add! 1100330055
num # => 10000000000000001100330055
num.add! 22004400
num # => 10000000000000001122334455
# A second way to see it: we've been modifying `num`, but since `original`
# is referencing the same object, its value has changed, too:
original # => 10000000000000001122334455
# With a Fixnum (small int), the value is derived from its memory address,
# so if we change the value of the address, then we are referencing a different
# number, not changing the number's value... there isn't an actual value
# available for us to change. Thus, a Fixnum is logically immutable,
# and also a true singleton object!
#
# I don't have time rn to figure out how to modify a local variable, but if I
# did, know that it would differ from the above example in that `original`
# would be unchanged.
require 'objspace'
ObjectSpace._id2ref(10<<1 | 1) # => 10
ObjectSpace._id2ref(11<<1 | 1) # => 11
ObjectSpace._id2ref(12<<1 | 1) # => 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment