Each object always has a singleton class. Period. No ifs, no buts, no exceptions.
Depending on how smart the compiler or interpreter is, it may or may not perform some performance optimizations. But, like all performance optimizations, this is not allowed to change the result of the program, so even if these performance optimizations lead to certain conditions where a particular singleton class does not actually exist, the program should still behave as if it existed, what you cannot say anyway. After all, this is pretty much the definition of "performance optimization."
Some Ruby implementations may do some optimizations, others may do other optimizations, some may not even optimize at all. You cannot tell by the result of your program, and you don't care, you don't care.
For example, YARV performs the following optimizations:
Since almost no objects have singleton methods, creating a single class for each object will be a waste of memory, so singleton classes are created lazily: when creating a singleton method ( def foo.bar or Object#define_singleton_method ) when you open a singleton class ( class << foo ) and when you request a singleton class object ( Object#singleton_class ).
Since almost every class has a kind of class method, the overhead of lazy creating a singleton class does not make sense, so for classes, a single class is always created with impatience.
But this is a private internal detail of the YARV implementation. JRuby can do it differently. IronRuby can do it differently. MacRuby can do it differently. MRuby can do it differently. Topaz can do it differently. Rubinius can do it differently. MagLev can do it differently. Even the next YARV patch level can do it differently.
If you look at the singleton class, it is there. If you do not look at it, it does not matter if he is there. So, semantically, he is always there.
source share