Can a Ruby Module Be Described as a Singleton Class

Can a Ruby module be described as a singleton class?

A ruby class is a module you can make instances of. Like a class, a module can have methods, but you cannot make an instance of a module. That's the only difference between them.

In practice, modules are commonly used for:

  • Name spaces
  • Mixins
  • To hold functions

Name Space

Here's an example of a module used as a name space:

module MyLib
class Foo
end
class Bar
end
end

The full name of these classes is MyLib::Foo and MyLib::Bar. Because they are contained in a namespace (which presumably is unique), the names Foo and Bar cannot conflict with a Foo or Bar defined in your program or in another library.

Mixin

Here's a module used as a mix-in:

module Mixin
def foo
puts "foo"
end
end

Since you can't make an instance of the Mixin module, you get access to foo by including (mixing in) the module:

class MyClass
include Mixin
end

MyClass.new.foo # => foo

Functions

Like a class, a module can hold functions that do not operate on any instance. To do that, you define class methods in the module:

module SomeFunctions
def self.foo
puts "foo"
end
end

A class method defined in a module is just like a class method defined in a class. To call it:

SomeFunctions.foo    # => foo

Ruby Singleton, module vs class

The simplest way to get an object in Ruby is to use, well, an object:

class << Foo = Object.new
attr_accessor :foo
end

Using either a module or a class is overkill, both have features you don't need.

What exactly is the singleton class in ruby?

First, a little definition: a singleton method is a method that is defined only for a single object. Example:

irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
from (irb):8

Instance methods are methods of a class (i.e. defined in the class's definition). Class methods are singleton methods on the Class instance of a class -- they are not defined in the class's definition. Instead, they are defined on the singleton class of the object.

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

You open the singleton class of an object with the syntax class << obj. Here, we see that this singleton class is where the singleton methods are defined:

irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false

So an alternative means of adding singleton methods to an object would be to define them with the object's singleton class open:

irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false

In summary:

  • methods must always belong to a class (or: be instance methods of some class)
  • normal methods belong to the class they're defined in (i.e. are instance methods of the class)
  • class methods are just singleton methods of a Class
  • singleton methods of an object are not instance methods of the class of the object; rather, they are instance methods of the singleton class of the object.

Why a module's singleton method is not visible in downstream eigenclasses where it gets mixed?

First of all, include does not include eigenclass methods as you might expect. Consider:

module Foo
class << self
def do_something
puts "Foo's eigenclass method does something"
end
end
end

module Bar
include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

Note that this is consistent with the behavior of classically defined class methods:

module Foo
def self.do_something
puts "Foo's class method does something"
end
end

module Bar
include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

A common idiom is to define the class methods in a submodule and then trigger a call to extend when the module is included:

module Foo
def self.included(base)
base.extend ClassMethods
end

module ClassMethods
def do_something
puts "Foo::ClassMethod's instance method does something"
end
end
end

module Bar
include Foo
end

puts Bar.do_something
# Foo::ClassMethod's instance method does something

The second thing to note is, that you are really including the instance methods of Automobile into the eigenclass of Vehicle, thus the instance methods of Automobile turn into (eigen)class methods of Vehicle.

Your Car class basically has nothing to do with all this. The only thing to note here is, that class inheritance also makes class methods available, whereas include does not. Example:

class Foo
def self.do_something
puts "Foo's class method does something"
end
end

class Bar < Foo
end

puts Bar.do_something
# "Foo's class method does something"

When is it wise to use Singleton classes in Ruby?

Note that a class mixing in the Singleton module is functionally equivalent to a class or module with 'class' methods and either a guaranteed initialization call or inline initialization. Compare this usage of Singleton:

require 'singleton'
class Bar
include Singleton
attr_reader :jam
def initialize
@jam = 42
end
def double
@jam *= 2
end
end

b1 = Bar.instance
b1.double
b2 = Bar.instance
b2.double
p b1.jam #=> 168

with this no-magic module:

module Foo
@jam = 42
def self.double
@jam *= 2
end
def self.jam
@jam
end
end

Foo.double
Foo.double
p Foo.jam #=> 168

In both cases you have a single global object that maintains state. (Because every constant you create in the global scope, including classes and modules, is a global object.)

The only functional difference is that with the Singleton you delay the initialization of the object until the first time you ask for it.

So, if you ever have 'class' methods on a class or module and you use those to change the state of that object (e.g. a class keeping track of all subclasses that inherit from it) you are essentially using a singleton.

Singleton module or class methods + class instance variables for singleton-like behaviour in Ruby?

Nothing, as you wrote your code--but a singleton is a class that only allows a single instance. Nothing in the second code snippet disallows instantiation of multiple instances.

What's the difference between a class and the singleton of that class in Ruby?

To answer your question directly: Module#define_method creates an instance method. A "class method" is an instance method on the singleton class (or eigenclass) of a Class object. I'm sure that sounds very confusing. Let me explain why Ruby includes the concept of "singleton classes" in the first place:

First, let me say that the basic "framework" of different object-oriented languages are quite varied. Ruby's design as regards objects, classes, metaclasses, etc. is by no means the only possible one, and the language could have been designed in a different way. Having said that, there are logical reasons why Ruby works the way it does. I'll try to explain as concisely as possible...

Think of a simple method call, like:

[1,2,3].first

Here we are calling a method called first, with an Array object as receiver. To process this method call, Ruby needs to search for a matching method definition, and execute it. Where does it start looking? Naturally, in the instance methods of Array. If it doesn't find it there, it will look in Array's superclass, then the superclass of the superclass, as well as Modules which are mixed into Array or its superclasses, etc.

"Class-based" (as opposed to prototype-based) object-oriented languages all work this way, more or less. If you've ever programmed in Java, or C++, or Python, this behavior should be familiar to you.

Now, the creator of Ruby wanted to also make it possible to add methods to just one object. In a prototype-based OO language, that would be easy, but how could it work in a class-based language? He made it possible by introducing the idea of "singleton classes" or "eigenclasses".

A "singleton class" is, simply, a class which has only one instance. I believe that rather than trying to keep track of a different singleton class for every single object, Ruby waits until the first time you try to access an object's singleton class, and then creates the class and inserts it into the object's inheritance chain dynamically.

As I just said, when a method is called, Ruby looks first in the object's class to find a matching definition, then the superclass, etc. Since singleton classes are inserted as the first link in an object's inheritance chain, they are the first place which Ruby will look for a method definition.

Bringing in the concept of "singleton classes" also solved another problem at the same time. In Java (for example), you can define static methods which are called on a class. In Ruby, people often want to do something similar. With "singleton" classes and methods, you can do just that: all you have to do is define a singleton method on a Class object.

(Remember that classes are also objects in Ruby. That's why the concept of "singleton" classes and methods can "kill 2 birds with 1 stone", as I explain above!)

EXTRA INFORMATION:

At the beginning, I mentioned "instance methods". I don't know if that might be confusing, or if you already know what "instance methods" are. When you define a Ruby class, like this...

class MyClass
def my_method
# do something
end
end

...then my_method will be added as an instance method of MyClass. When Ruby searches an object's class, superclass, etc. for a method definition, what it actually looks at are their instance methods. So an object's "methods" are the instance methods of its class, plus the instance methods of the superclass, the superclass of the superclass, etc.

About how singleton classes interact with method lookup in Ruby, there is a slight inconsistency which I didn't mention above. If you want to understand in detail:

Singleton classes of class objects are treated a little differently from singleton classes of other objects in general. If you have a class A which inherits from another class B, and B has singleton methods, A will inherit not just the instance methods, but also the singleton methods of B. In other words, B's singleton class is treated as a superclass of A's singleton class. This is not true of the singleton classes of any other objects.

Calling a singleton method within the singleton class in Ruby?

You can define the default value as:

module MyModule
class << self

def process_item(item)
item.capitalize
end

def foo=(item)
@foo_ref=process_item(item)
end

def foo
@foo_ref ||= "initial foo"
end
end
end

What you were trying to do was to set foo to the singleton class, instead of setting foo to the class.

Ruby ancestors method for singleton class objects

I think you'll really like the ruby 2.1 then!

$ rbenv local 2.1.0
roman.brodetski@nb-rbrodetski []
$ irb
...
irb(main):008:0> B.singleton_class.ancestors
=> [#<Class:B>, ClassMethods, #<Class:A>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
irb(main):009:0>

I also think it's a great thing that your mind is synchronized with the language developers!

Here is the redmine issue: https://bugs.ruby-lang.org/issues/8035



Related Topics



Leave a reply



Submit