Forum: Ruby why this behaves like singleton

Posted by Javier Isassi (cabazorro)
on 2012-11-27 17:00
Attachment: whySing.rb (459 Bytes)
The attached code prints:

print g1 locks
5
print g2 locks
5
3


I would expect g2 to print 3. Why the Lock object behaves
like singleton?

Thanks.

Javier.
Posted by Jan E. (jacques1)
on 2012-11-27 17:20
Hi,

a class variable (in your case @@locks) is shared among the class and 
all instances of the class -- as well as all subclasses and their 
instances. So when g1 or g2 do something with @@locks, it's always the 
same array.

I think you generally misunderstand the difference between the various 
types of variables. For example, the variable @lock in @lock = 0 is 
completely different from the one you use in the initialize method, and 
in your case it's simply useless. Ruby is not Java where this syntax is 
used to set default values.

So you might wanna read up on this topic:
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes

You should generally avoid class variables unless you really know what 
you're doing. Use instance variables or class instance variables 
depending on the specific purpose.

To fix your code, replace @@locks with an instance variable and set it 
in the correct context:

----------------------------
class Locks
  def initialize ( rd )
  @locks = []
    rd.each do |k|
      @locks << Lock.new(rd)
  end
end

  def printLocks
    @locks.each do |l|
      puts l.glock()
        end
  end
end
----------------------------
Posted by "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2012-11-27 17:21
(Received via mailing list)
On Tue, Nov 27, 2012 at 5:00 PM, Javier Isassi <lists@ruby-forum.com> 
wrote:
> like singleton?
class Lock
   @lock = 0

# This variable is not the same as the one used below in initialize
and glock methods. The reason is that @xxx refers to an instance
variable of the object that happens to be self in that scope, and in
this case the object is the Lock class itself, while in the initialize
and glock methods, it's a specific instance of the Lock class. So, in
summary, you can remove this line.

   def initialize(r)
       @lock = r
   end
   def glock()
      @lock
   end
end

class Locks
   @@locks = []

# A variable prefixed with @@ is a class variable. It is shared among
the class and all its subclasses. Every reference to this variable in
this scope or in instance methods of this class or any subclass will
refer to the same object. You most certainly don't want this. So
remove this and change it with @locks = [] inside the initialize
method, which creates an instance variable of the object being
initialized.

   def initialize ( rd )
     rd.each do |k|
         @@locks << Lock.new(rd)
     end
   end

   def printLocks
       @@locks.each do |l|
       puts l.glock()
       end
   end
end

I would try:

class Lock
  attr_reader :lock
  def initialize r
    @lock = r
  end
end

class Locks
  def initialize lock_ids
    @locks = []
    lock_ids.each {|id| @locks << Lock.new(id)}
  end

  def print_locks
    @locks.each {|lock| puts lock.lock}
  end
end

1.9.2p290 :019 > g1 = Locks.new([5])
 => #<Locks:0x00000001744568 @locks=[#<Lock:0x00000001744518 @lock=5>]>
1.9.2p290 :020 > puts "print g1 locks"
print g1 locks
 => nil
1.9.2p290 :021 > g1.print_locks
5
 => [#<Lock:0x00000001744518 @lock=5>]
1.9.2p290 :022 > g2 = Locks.new([3])
 => #<Locks:0x0000000174fc38 @locks=[#<Lock:0x0000000174fbe8 @lock=3>]>
1.9.2p290 :023 > puts "print g2 locks"
print g2 locks
 => nil
1.9.2p290 :024 > g2.print_locks
3


Jesus.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.