[#1026] Is this a bug? — Dave Thomas <Dave@...>

18 messages 2000/01/03

[#1084] Infinite loop — Dave Thomas <Dave@...>

17 messages 2000/01/11

[#1104] The value of while... — Dave Thomas <Dave@...>

24 messages 2000/01/11

[ruby-talk:01129] Class variables...

From: Clemens Hintze <clemens.hintze@...>
Date: 2000-01-12 10:44:56 UTC
List: ruby-talk #1129
David Suarez de Lis writes:
> Hi all,

Hi you, :-)

>  I am brand new to Ruby's world, but I find it pretty
> interesting... :)

then let me take the chance to welcome you to our interesting world of
Ruby. :-)

>  I have a doubt, though, I haven't been able to solve through
> testing or documentation...

No problem, this is the reason for that this mailing list was created
for (officially. In reality matz has created this list to address my
handicap, that I has learned the wrong language and not Japanese;
because most of the gurus are on the japanese mailing list; but we are
on the way to change this ;-))))

>  Say I have a class person and a variable @population.

First mistake here. The sign '@' denotes *instance* variables. Class
variables, however, are not instance variables. In fact Ruby has no
true class variables yet (but it has class methods :-). I don't know,
if that is going to change in future ... matz?)

> 
> class Person
>     @population = 0
>     def new(the_name = nil)
>         @name = the_name
>         @Person::population += 1
>     end
> end

May I suggest to let me insert a small script below, that will deal
with your class? You could store it into a file and execute it. I
don't know, if you have already recognized it, but Ruby has *true* GC
(mark and sweep schme). Normally it is not very predictable, when an
object will be reclaimed! For that reason, I have inserted 'GC.start'
calls to invoke start GC at a certain point. Under normal
circumstances you would not have to call it by your own!

A further disadvantage of this *true* GC (the 1st one is the
unpredictability, if you will count it as disadvantage) is, that
finalization of objects is a little bit complicate to understand.
There is no automatic call to a certain method forseen for an object
being subject to deletion like in other languages like Python, Perl or
Java!

You have to use 'ObjectSpace.define_finalizer' to attach a finalizer
Proc instance, that will be called during GC for that object! BUT PAY
ATTENTION, YOU MUST NOT STORE ANY REFERENCE TO THAT OBJECT INTO SUCH A
FINALIZER PROC. If you would do so, the GC would think, that the
object is needed yet, and will never be deleted therefore. This
problem is comparable with the circular reference problem in Reference
Counting Garbage Collectors.

But please bear also in mind, that if you create a Proc instance (via:
proc, lambda or Proc.new) *within* a method, an invisible variable
'self', pointing to the instance for that this method was called for,
will also be stored in that Proc object, becaus the Proc instance
resembles a closure that will remember the whole context that was
valid during instantiation/creation. So that is the reason, why you
have to use class methods for creating/generation lambda expressions
to announce for finalization.

It is a little bit confusing, isn't it? ;-) Perhaps the script makes
things clear:

----------------------8X----------------------------
#!/bin/env ruby

require "final"

class Person
    Population = [0]

    # Following method will be called automatically during instanciation
    def initialize(name)
        @name = name
        Population[0] += 1
        print name, " is born ...\n"
        ObjectSpace.define_finalizer(self, Person::died(name))
        # Pay attention!!! Following would not work! Reason is implicite
        # 'self' pointer created by 'lambda'!
        # ObjectSpace.define_finalizer(self, lambda{ Population[0] -= 1 })
    end

    # Follwing class method is a Proc instance generator ;-)
    def Person.died(who)
        Proc.new do
            print who, " died ...\n"
            Population[0] -= 1
        end
    end

    # Also a class method for reporting the size of the population.
    def Person.report
        if Population[0] > 0
            print "Population: #{Population[0]} persons.\n"
        else
            print "No population at all!\n"
        end
    end
end

folks = []
for name in "A".."Z"
    folks << Person.new(name)
end
Person.report
while not folks.empty?
    folks.shift  # Remove first Person from Array
    GC.start     # Comment that line to see a difference
end
GC.start         # Comment that line to see a difference
Person.report
exit 0
----------------------8X----------------------------

>  Ie. I want to be able to access that class variable from
> objects... Also, I assume END {} allows us to put conditions for GC?
> Like END { @Person::population -= 1 }

No! END is like system call 'atexit' in C!

> 
> thanks for your help,
> d@

It was my pleasure. I know, that my explanations sound a little bit
confusing, perhaps. If you have any questions, do not hesitate to ask!
:-)

ciao,
\cle

In This Thread