a = 1
a += 1
=> 2
The original object 1 is now unused and this is not very performative. Why are integers immutable in ruby? I've looked on stackoverflow but could find no explanation.
a = 1
a += 1
=> 2
The original object 1 is now unused and this is not very performative. Why are integers immutable in ruby? I've looked on stackoverflow but could find no explanation.
Integers, and all Numerics, are immutable so there is only ever one of each. We can see this by checking their #object_id.
2.6.4 :001 > a = 1
=> 1
2.6.4 :002 > a.object_id
=> 3
2.6.4 :003 > 1.object_id
=> 3
2.6.4 :004 > b = 1
=> 1
2.6.4 :005 > b.object_id
=> 3
This behavior is also documented in Numeric.
Other core numeric classes [other than Numeric] such as Integer are implemented as immediates, which means that each Integer is a single immutable object which is always passed by value. There can only ever be one instance of the integer 1, for example. Ruby ensures this by preventing instantiation. If duplication is attempted, the same instance is returned.
Having a single immutable object for each Integer saves memory in normal use, you're going to use 1 a lot. Everyone sharing the same 1 saves a lot of memory, but that means it must be immutable else adding to one object would change other objects and that would be bad.
Not having to constantly deallocate and allocate the same Integer over and over is faster and reduces memory fragmentation. If they're really unused, Ruby will garbage collect them. Ruby's garbage collection is constantly being improved and can be tweaked with many environment variables.
It also simplifies their implementation and makes them more performant. Immutable objects can cache any calculations confident the cache will never need to be invalidated.
Why are integers immutable in ruby? I've looked on stackoverflow but could find no explanation.
Let's assume that Integers were mutable:
1 << 1
1 + 1
#=> 4
I am guessing that the reason that you find no explanation is that most assume it is self-evident that the ability to change the value of 1 to be anything other than 1 would lead to an absolutely insane maintenance nightmare.
Think of the ability to mutate integers and what that would entail for the ruby programmer. It would give them too much power in changing how the language observes the world. An integer object is a sequence of binary numbers in memory and if you increment the object by one, is it still one? No. That's why Ruby uses variables to point to the object rather than to mutate it.
Immutable integers save on consumption in the long run. I think what you are questioning here is the decision of ruby to make the original object immutable and to store it in memory rather than mutate it, which increases memory consumption? Well, a is not a global variable and should be cleared by garbage collection eventually. Ruby uses DRY principles for object allocation and it makes sense to retain objects rather than create them over and over. If you have more objects than ruby can fit into memory, it must allocate more memory, which is expensive on the OS but your code should be cognisant of that. Ruby does free memory when there is too much allocated. Ruby objects are stored in Ruby object heap rather than malloc heap which the garbage collector cleans often.
If integers were mutable then modifying a variable that is used elsewhere in an application would cause hard-to-fix regressions and would cause a lot of issues in web applications. As for the concern of retention and performance, look at the following example:
require 'newrelic_rpm'
a = 0
loop do
a += 1
if a % 10_000 = 0
p a
p NewRelic::Agent::Samplers::MemorySampler.new.sampler.get_sample
end
end
Observe how many objects are 'kept' and how much memory is consumed by the process. Now, think of how many objects are going to be kept in a real world program and think if the memory consumption will be a real issue. If you do find yourself encountering this issue, to which I don't think you will, see it as a notification to improve your code.