Why 'Self' Method of Module Cannot Become a Singleton Method of Class

Why 'self' method of module cannot become a singleton method of class?

If you want to have both class methods and instance methods mixed into a class when including a module, you may follow the pattern:

module YourModule
module ClassMethods
def a_class_method
puts "I'm a class method"
end
end

def an_instance_method
puts "I'm an instance method"
end

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

class Whatever
include YourModule
end

Whatever.a_class_method
# => I'm a class method

Whatever.new.an_instance_method
# => I'm an instance method

Basically to over-simplify it, you extend to add class methods and you include to add instance methods. When a module is included, it's #included method is invoked, with the actual class it was included in. From here you can extend the class with some class methods from another module. This is quite a common pattern.

See also: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

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"

Not use self in every class method and not use singleton model in ruby

(this was already mentioned by engineersmnky in the comments)

You could extend your class with a module that holds your class methods (that module can be nested right within your class):

class Foo
module ClassMethods
def bar
# Do something
end
end

extend ClassMethods
end

You can also move it outside your class, even in its own file (this can be useful structure-wise or if there are many class methods):

# foo/class_methods.rb
class Foo
module ClassMethods
def bar
# Do something
end
end
end

# foo.rb
class Foo
extend ClassMethods
end

Methods defined via extend can even be overridden in the base class:

class Foo
module ClassMethods
def bar
123
end
end
end

class Foo
extend ClassMethods

def self.bar
super * 2
end
end

Foo.bar #=> 246

This is especially useful if you want to add custom functionality when extending multiple classes with the same module (think of shared class methods).

When to use self in module's methods

Use self in each method definition if you want the methods to be defined only in the singleton class of the module (where the methods defined using self live). Omit self and extend self if you want the methods of the module to be defined as instance methods and singleton methods at the same time.

For instance, you can call the method using RG::Stats.sum(array) and still have it listed by the instance_methods method if you do this:

module RG::Stats
extend self

def sum(a, args = {})
a.inject(0){ |accum, i| accum + i }
end
end

This way, the sum method is defined as an instance method and it is included in the singleton class of the module after using extend self.

You can check the instance methods of RG::Stats module to verify this:

RG::Stats.instance_methods
=> [:sum]

With this technique you don't have to worry about defining the method without the self keyword because modules can't have instances so it cannot be called like an instance method of RG::Stats module. It can only be called as a singleton method RG::Stats.sum(array) thanks to the extend self statement.

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.

Why do methods inside a class become instance methods instead of becoming singleton methods of the class itself?

It works similarly to message sends and constant lookup:

  • The general format of a message send is foo.bar, which sends the message bar to foo. If you leave out foo, the message will be sent to the default receiver (which is self).
  • The general format of a constant lookup is Foo::Bar, which looks up the constant Bar in the module Foo. If you leave out Foo, the constant will be looked up in the default constant context (or cref).
  • The general format of a method definition is def foo.bar, which defines the method bar in the singleton class of foo. If you leave out foo, the method will be defined in the default definition context (or default definee):

    • At the top-level, the default definee is Object. (Also, the methods become private.)
    • Within a module declaration body, the default definee is self (and not self's singleton class, like you assumed!)
    • Within a method body, the default definee is the syntactically enclosing module. (Put another way: def doesn't change the default definee.)
    • instance_eval changes the default definee to the receiver's singleton class
    • class_eval changes the default definee to the receiver

In Ruby, in a method defined in class self, why can't a constant defined on the superclass be access without self?

You have encountered a common Ruby gotcha - constant lookup.

The most important concept in constant lookup is Module.nesting (unlike in method lookup, where the primary starting point is self). This method gives you the current module nesting which is directly used by the Ruby interpreter when resolving the constant token. The only way to modify the nesting is to use keywords class and module and it only includes modules and classes for which you used that keyword:

class A
Module.nesting #=> [A]

class B
Module.nesting #=> [A::B, A]
end
end

class A::B
Module.nesting #=> [A::B] sic! no A
end

In meta programming, a module or class can be defined dynamically using Class.new or Module.new - this does not affect nesting and is an extremely common cause of bugs (ah, also worth mentioning - constants are defined on the first module of Module.nesting):

module A
B = Class.new do
VALUE = 1
end

C = Class.new do
VALUE = 2
end
end

A::B::VALUE #=> uninitialized constant A::B::VALUE
A::VALUE #=> 2

The above code will generate two warnings: one for double initialization of constant A::VALUE and a second for reassigning the constant.

If it looks like "I'd never do that" - this also applies to all the constants defined within RSpec.describe (which internally calls Class.new), so if you define a constant within your rspec tests, they are most certainly global (unless you explicitly stated the module it is to be defined in with self::)

Now let's get back to your code:

class SubExample < SuperExample
puts Module.nesting.inspect #=> [SubExample]

class << self
puts Module.nesting.inspect #=> [#<Class:SubExample>, SubExample]
end
end

When resolving the constant, the interpreter first iterates over all the modules in Module.nesting and searches this constant within that module. So if nesting is [A::B, A] and we're looking for the constant with token C, the interpreter will look for A::B::C first and then A::C.

However, in your example, that will fail in both cases :). Then the interpreter starts searching ancestors of the first (and only first) module in Module.nesting. SubrExample.singleton_class.ancestors gives you:

[
#<Class:SubExample>,
#<Class:SuperExample>,
#<Class:Object>,
#<Class:BasicObject>,
Class,
Module,
Object,
Kernel,
BasicObject
]

As you can see - there is no SuperExample module, only its singleton class - which is why constant lookup within class << self fails (print_constant_fails).

The ancestors of Subclass are:

[
SubExample,
SuperExample,
Object,
Kernel,
BasicObject
]

We have SuperExample there, so the interpreter will manage to find SuperExample::A_CONSTANT within this nesting.

We're left with print_constant_works_2. This is an instance method on a singleton class, so self within this method is just SubExample. So, we're looking for SubExample::A_CONSTANT - constant lookup firstly searches on SubExample and, when that fails, on all its ancestors, including SuperExample.

Calling a singleton method within an instance method in a module that extends itself

Kernel.abort is defined by first defining an instance method Kernel#abort and then making it also a singleton method with module_function. (This is definitely the case in Rubinius; I couldn't find it in the MRI source but see below.) module_function makes a copy of the method. When you redefine abort you redefine the instance method but not the singleton copy.

Object includes Kernel, so when you say abort you get the instance method, which you've redefined, but when you say Kernel.abort you get the singleton method, which you haven't redefined.

If you really wanted to use recursion in abort, or just to demonstrate that this explanation is correct, call module_function :abort after redefining the method. The singleton method will be updated to be the same as the instance method and both methods will recurse.

Note that you didn't need to extend self to redefine the instance version of abort. Since Kernel is already included in Object, you only needed to redefine the instance method for all objects to see the redefined version. On the other hand, if Kernel had used extend self to expose #abort in the first place, we could redefine it without any complications.

The following demonstrates that the lack of recursion happens with user-defined, pure Ruby methods, i.e. that module_function is responsible and native methods are not:

$ cat foo.rb
module Foo
def bar
puts "old version"
end
module_function :bar
end

module Foo
def bar
puts "new version"
Foo.bar
end
end

Object.include Foo
bar
$ ruby foo.rb
new version
old version

Why am I able to call the class method as if it were an instance method here?

When inside an abstract class, the self refers to the proper class, not the object. That's why you can access the method without explicitly telling self

class self idiom in Ruby

First, the class << foo syntax opens up foo's singleton class (eigenclass). This allows you to specialise the behaviour of methods called on that specific object.

a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"

a = 'foo' # new object, new singleton class
a.inspect # => "foo"

Now, to answer the question: class << self opens up self's singleton class, so that methods can be redefined for the current self object (which inside a class or module body is the class or module itself). Usually, this is used to define class/module ("static") methods:

class String
class << self
def value_of obj
obj.to_s
end
end
end

String.value_of 42 # => "42"

This can also be written as a shorthand:

class String
def self.value_of obj
obj.to_s
end
end

Or even shorter:

def String.value_of obj
obj.to_s
end

When inside a function definition, self refers to the object the function is being called with. In this case, class << self opens the singleton class for that object; one use of that is to implement a poor man's state machine:

class StateMachineExample
def process obj
process_hook obj
end

private
def process_state_1 obj
# ...
class << self
alias process_hook process_state_2
end
end

def process_state_2 obj
# ...
class << self
alias process_hook process_state_1
end
end

# Set up initial state
alias process_hook process_state_1
end

So, in the example above, each instance of StateMachineExample has process_hook aliased to process_state_1, but note how in the latter, it can redefine process_hook (for self only, not affecting other StateMachineExample instances) to process_state_2. So, each time a caller calls the process method (which calls the redefinable process_hook), the behaviour changes depending on what state it's in.



Related Topics



Leave a reply



Submit