Skip to content

Instantly share code, notes, and snippets.

@jcoglan
Created February 18, 2013 20:02
Show Gist options
  • Save jcoglan/4980199 to your computer and use it in GitHub Desktop.
Save jcoglan/4980199 to your computer and use it in GitHub Desktop.

Core ideas

  • An Object is a set of instance variables and a pointer to a 'singleton class'.
  • Properties are looked up in the instance variables, methods are dispatched via the singleton class.
  • Module is a subtype of Object. A Module is a set of methods and an ordered list of zero-or-more 'parent' modules.
  • Module A becomes a parent of module B via B.include(A).
  • Method lookup works by doing a depth-first right-to-left search of a module tree.
  • Class is a subtype of Module. A Class is a Module that can be instantiated.
  • A Class has only one 'superclass'. A class includes its superclass as its first parent module for the purposes of method dispatch. A class's singleton class includes the superclass's singleton class as its first parent.
  • The default superclass of all classes is Object.
  • Object includes the Kernel module as a parent.

Warts

  • Although Class is a subtype of Module, you cannot call B.include(A) if A is a Class.
  • Singleton classes are not really classes. You cannot instantiate or inherit from them.

Sugar

  • obj.extend(M) is sugar for obj.singleton_class.include(M).
@r4vi
Copy link

r4vi commented Feb 18, 2013

what is all this stuff I see about people doing class Foo << self (extending the module onto itself?)

@Peeja
Copy link

Peeja commented Feb 18, 2013

@r4vi: I think you're conflating two things. One is opening the singleton class of an object:

o = Object.new

class << o
  def foo
    10
  end
end

o.foo  # => 10

which also works on classes (and modules), since they're a kind of object too. Inside a class definition, self is the class being defined, so:

class Bar
  class << self
    def foo
      10
    end
  end
end

Bar.foo  # => 10

which is the same as

class Bar
end

class << Bar
  def foo
    10
  end
end

Bar.foo  # => 10

Unrelated, you can also mix a module into the module's metaclass. That sounds complicated, but it means that the module's methods (which are instance methods) become available on the module object itself. Thus:

module Baz
  def qux
    20
  end
end

Baz.qux  # => Error: NoMethodError

Baz.extend(Baz)
Baz.qux  # => 20

# Nothing special about Baz, though.
o = Object.new
o.extend(Baz)
o.qux  # => 20

You can also do this upfront like so:

module Baz
  extend self

  def qux
    20
  end
end

There happens to be another way to achieve the same end, which for some reason is called module_function:

module Baz
  module_function

  def qux
    20
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment