2

I am writing a module with method foo, which calls a class method bar on the receiver's class. My current approach is to use self.class.bar, which works fine unless the class method is defined in an instance class instead of a "real" one:

module M
  def foo
    self.class.bar
  end
end

obj = Object.new
class << obj
  include M
  def self.bar
    42
  end
end

obj.foo # => NoMethodError: undefined method `bar' for Object:Class

This makes sense because obj.class does not return singleton classes. I could use obj.singleton_class instead, and everything would run smoothly:

module M
  def foo
    self.singleton_class.bar
  end
end

obj = Object.new
class << obj
  include M
  def self.bar
    42
  end
end

obj.foo # => 42

only if the method is defined on a singleton class for the same reason as above. Worse still, it creates a new singleton class for every receiver, something I want to avoid as these might be a fair amount of objects. So instead, I want some way to retrieve an object's singleton class if and only if it is already defined, i.e. something of the type obj.has_singleton_class ? obj.singleton_class : obj.class. I couldn't find any way to perform this check though.

sawa
  • 165,429
  • 45
  • 277
  • 381
azgult
  • 542
  • 3
  • 10

1 Answers1

5

Every object always has a singleton class in Ruby. The specific implementation you use (MRI, YARV, Rubinius, JRuby, IronRuby, MacRuby, MagLev, MRuby, etc.) may or may not optimize memory usage by not allocating memory for a singleton class that isn't used, but that's a private internal implementation detail, an invisible transparent compiler optimization. Whenever you go looking for a singleton class, it'll be there.

Well, actually, that's not quite true. Immediate values, i.e. Integers, Symbols and Floats cannot have singleton classes.

So, those three will never have a singleton class, all others always have a singleton class.

user513951
  • 12,445
  • 7
  • 65
  • 82
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • This answer needed an update, since `Fixnum` is deprecated in Ruby 2.4. See [this answer](http://stackoverflow.com/a/21411269/513951) by @JörgWMittag ;) – user513951 Dec 21 '16 at 00:10