class Integer
def prime?
return false if self < 2
return @is_prime if @prime_cached @prime_cached = true
(2…(self ** 0.5)).each do |i|
return (@is_prime = false) if i.prime? and self % i == 0
end @is_prime = true
end
end
I want each integer to remember if it’s a prime number or not.
As the calculation uses cache of smaller prime numbers, it runs fast.
But I’m not sure if the cache is preserved after GC runs (when nothing
refers to the integers).
If the cache is not preserved, it’s no use.
My first idea was keeping the cache in a class variables like
@@prime_numbers and @@max_cached.
But I think it would be better if each object remembers its own state.
I want each integer to remember if it’s a prime number or not.
As the calculation uses cache of smaller prime numbers, it runs fast.
But I’m not sure if the cache is preserved after GC runs (when nothing
refers to the integers).
If the cache is not preserved, it’s no use.
IIRC an Integer’s instance variables are eternal due to various
implementation details.
But I’m not sure if the cache is preserved after GC runs (when nothing
refers to the integers).
If the cache is not preserved, it’s no use.
My first idea was keeping the cache in a class variables like
@@prime_numbers and @@max_cached.
But I think it would be better if each object remembers its own state.
What do you think?
I’m pretty sure that your concern about GC is moot, but just as long
as you stay with in the range of Fixnums. Fixnums are ‘immediate’
objects, and never get collected. I Bignums are another matter.
For Fixnums your code works as is. The @prime_cached iv is not needed
however, here’s another way to do it:
class Integer
def prime?
return false if self < 2
return @is_prime unless @is_prime.nil?
(2…self**0.5).each do | i |
return (@is_prime = false) if i.prime? and self
% i == 0
end @is_prime = true
end
end
Now there are 100000 integers in the memory which won’t die.
No there aren’t. Immediate values don’t allocate anything in memory.
[… an accurate description of class Fixnum’s implementation]
Also, since a Fixnum is immediate, it doesn’t “have” instance
variables because there’s no Object to store them in. Instead they
are stored somewhere else. (Where isn’t terribly important.)
The instance variables will consume memory, of course.
Now there are 100000 integers in the memory which won’t die.
No there aren’t. Immediate values don’t allocate anything in memory.
They aren’t pointers (even though under the hood Ruby coerces them to
the same type as non-immediate values that are pointers). Immediate
values aren’t garbage collected because there is nothing to garbage
collect. They don’t point to anything. What is there to collect?
Think of C. Does “long i ; i = 0 ; i = 1 ; i = 2 ; i = 3” consume any
more memory than “long i ; i = 0”? No, because the only memory
allocated is for the long variable “i”. The values 0, 1, 2, 3, are
just constants that are copied (one after the other) into that single
previously allocated space. Ruby’s immediate values are just like C
longs (in fact, under the hood, they are just C longs). Creating
them doesn’t consume memory, it just copies them into a pre-existing
chunk of memory that was already allocated by the Ruby interpreter.
If you create lots of references to immediate values, eg. by writing
" a = (1…100000).collect {|i| i } ", then that will consume memory.
But that memory isn’t being used to create immediate values, it’s
being used to store those values inside an object. Once that object
is no longer referenced the memory is available to be recycled by the
garbage collector. All memory allocation/deallocation is associated
with the non-immediate object that holds those references. The
immediate values themselves allocate no memory at all.
Now there are 100000 integers in the memory which won’t die.
No there aren’t. Immediate values don’t allocate anything in memory.
They aren’t pointers (even though under the hood Ruby coerces them to
the same type as non-immediate values that are pointers). Immediate
values aren’t garbage collected because there is nothing to garbage
collect. They don’t point to anything. What is there to collect?
Think of C. Does “long i ; i = 0 ; i = 1 ; i = 2 ; i = 3” consume any
more memory than “long i ; i = 0”? No, because the only memory
allocated is for the long variable “i”. The values 0, 1, 2, 3, are
just constants that are copied (one after the other) into that single
previously allocated space. Ruby’s immediate values are just like C
longs (in fact, under the hood, they are just C longs). Creating
them doesn’t consume memory, it just copies them into a pre-existing
chunk of memory that was already allocated by the Ruby interpreter.
I understand what you said.
But the integers that I created have additional information.
So not that simple.
Can you read the code I wrote and reconsider such a case?
Immediate
them doesn’t consume memory, it just copies them into a pre-existing
chunk of memory that was already allocated by the Ruby interpreter.
I understand what you said.
But the integers that I created have additional information.
So not that simple.
Can you read the code I wrote and reconsider such a case?
It will work. The instance variables are stored elsewhere.
Also, since a Fixnum is immediate, it doesn’t “have” instance
variables because there’s no Object to store them in. Instead they
are stored somewhere else. (Where isn’t terribly important.)
Thanks for pointing that out. I had never thought to wonder where
immediate objects put their instance variables. Live and learn!
I hadn’t either, and it once again impressed me with Ruby.
About 20 years ago there was a raging discussion between advocates of
REALLY dynamic OO languages like self, and more traditional dynamic OO
languages like Smalltalk.
Dave Ungar, who did most of if not all of the implementation of
Berkley’s Smalltalk, and wrote his PhD dissertation on analysing it’s
performance, and then went on to develop self, used to love to ask
people who had done Smalltalk implementations to dynamically add an
instance variable to Object, something which invariably crashed, or
inf-looped whatever Smalltalk VM it was tried on.
Ruby not only can do that, but it can add instance variables to
instances.
Also, since a Fixnum is immediate, it doesn’t “have” instance
variables because there’s no Object to store them in. Instead they
are stored somewhere else. (Where isn’t terribly important.)
Thanks for pointing that out. I had never thought to wonder where
immediate objects put their instance variables. Live and learn!
Jeremy H.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.