2
\$\begingroup\$

When I need a singleton class in my Ruby code (for example, single logger for multiple classes) I usually use code like this:

class Parent_Singleton
  @singleton = nil

  def self.new
    @singleton || (@singleton = super)
  end
end 

This approach allows me to avoid using the module Singleton (because I don't want to use a special method instance to get an object of this class, I just want to use the usual Parent_Singleton.new in any part of my code to get my singleton object).

Another advantage of this approach is the ability to avoid using class variables @@singleton which of course is a bad practice because of its behavior in inheritance. My code doesn't have this issue:

class Child_Singleton < Parent_Singleton
end

p1 = Parent_Singleton.new
p2 = Parent_Singleton.new
c1 = Child_Singleton.new
c2 = Child_Singleton.new

p1 == p2 # => true
c1 == c2 # => true
p1 == c1 # => false
p2 == c2 # => false

If I need to store some variable data in my class, it's also not a problem:

class Parent_Class
  @singleton = nil
  @some_data = ''

  class << self
    def new
      @singleton || (@singleton = super)
    end

    def some_data
      @some_data
    end

    def some_data=(value)
      @some_data = value
    end
  end
end

class First_Child_Class < Parent_Class
end

class Second_Child_Class < Parent_Class
end

Parent_Class.some_data = 'Parent'
First_Child_Class.some_data = 'First_Child'
Second_Child_Class.some_data = 'Second_Child'

puts Parent_Class.some_data # => Parent
puts First_Child_Class.some_data # => First_Child
puts Second_Child_Class.some_data # => Second_Child

So my question is: if this code is bad, what's wrong with it? If this code is good, why the most of the examples worldwide suggest using either Singleton module (with instance method) or class variable-based singleton classes instead?

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

The Singleton module in Ruby for instance also guarantees synchronised access, e.g. if multiple threads try to create an instance your implementation would not work.

https://github.com/ruby/ruby/blob/master/lib/singleton.rb#L112-L168

It's also a convention (in other programming languages too) to call the method instance or getInstance. Calling several times new and always getting the same instance seems not very accurate.

I'm not sure I understand the use case of storing data beside the object rather than in the actual object.

Btw: In Ruby, classes are spelled in CamelCase and not Snake_Case.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.