Singleton classes and Namespce

Do singleton classes not get the same namespace treatment as normal
classes?

  module M
    class X; end
  end

  o = Object.new
  => #<Object:0x7fc61f1a1e58>

  (class << o; self; end).class_eval{ include M }
  => #<Object:0x7fc61f1a1e58>

  def o.x; X; end

  o.x
  => NameError: uninitialized constant X
    from (irb):6:in `x'
    from (irb):7

The "(class << o; self; end).class_eval{ include M }" is effectively
the same as "o.extend M" but I want to emphasize the use of #include.

It of course works fine if I use an explicit class.

  class O
    include M
    def x; X; end
  end

  O.new.x
  => M::X

Do singleton classes not get the same namespace treatment as normal
classes?

I think so.

module M
class X; end
end

o = Object.new
=> #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M }
=> #<Object:0x7fc61f1a1e58>

def o.x; X; end

This cannot work since X is not statically in scope.

o.x
=> NameError: uninitialized constant X
from (irb):6:in `x'
from (irb):7

The "(class << o; self; end).class_eval{ include M }" is effectively
the same as "o.extend M" but I want to emphasize the use of #include.

It of course works fine if I use an explicit class.

class O
include M
def x; X; end
end

O.new.x
=> M::X

Yes, but you also changed something else: you defined the method
inside the class body. So you did not only switch from class to
singleton class but you also changed the lookup. It works if you
define the method in the class body in the same way as you did for
class O:

irb(main):001:0> module M
irb(main):002:1> class X; end
irb(main):003:1> end
=> nil
irb(main):004:0> o = Object.new
=> #<Object:0x1016f240>
irb(main):005:0> (class << o; self; end).class_eval do
irb(main):006:1* include M
irb(main):007:1> def x; X; end
irb(main):008:1> end
=> nil
irb(main):009:0> o.x
=> M::X
irb(main):010:0> (class << o; self; end).class_eval do
irb(main):011:1* def y; X; end
irb(main):012:1> end
=> nil
irb(main):013:0> o.y
=> M::X
irb(main):014:0>

Kind regards

robert

···

2010/6/6 Intransition <transfire@gmail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Ah, but constant lookup is supposed to check the ancestors if the
constant is not found in the scope. M should be among the ancestors of
o's singleton class, shouldn't it? I would have expected this to work.
OTOH, constant lookup is confusing.

This way works:

module M
   class X; end
end

o = Object.new # => #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M } # => #<Object:0x7fc61f1a1e58>
#or o.extend M as well, presumably

  class<<o
    def x; X end
  end

o.x #=>M::X

See http://ruby.runpaint.org/variables#constants in which the lookup
rules are summarized as:
  (Module.nesting + container.ancestors + Object.ancestors).uniq
#slightly paraphrased

I guess the key point to understand is that for singleton methods,
container is the (static) module of class enclosing the singleton
method, NOT the singleton class that they affect.

···

On 6/7/10, Robert Klemme <shortcutter@googlemail.com> wrote:

2010/6/6 Intransition <transfire@gmail.com>:

Do singleton classes not get the same namespace treatment as normal
classes?

I think so.

module M
   class X; end
end

o = Object.new
=> #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M }
=> #<Object:0x7fc61f1a1e58>

def o.x; X; end

This cannot work since X is not statically in scope.

Do singleton classes not get the same namespace treatment as normal
classes?

I think so.

module M
class X; end
end

o = Object.new
=> #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M }
=> #<Object:0x7fc61f1a1e58>

def o.x; X; end

This cannot work since X is not statically in scope.

Ah, but constant lookup is supposed to check the ancestors if the
constant is not found in the scope. M should be among the ancestors of
o's singleton class, shouldn't it?

It does but you are not in the scope of the singleton class. Rather
you are in the toplevel (or any other) scope when you do "def o.x; X;
end".

I would have expected this to work.
OTOH, constant lookup is confusing.

This way works:

module M
class X; end
end

o = Object.new # => #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M } # => #<Object:0x7fc61f1a1e58>
#or o.extend M as well, presumably

class<<o
def x; X end
end

o.x #=>M::X

That's basically the same what I did: you create the method in the
singleton class's scope.

See http://ruby.runpaint.org/variables#constants in which the lookup
rules are summarized as:
(Module.nesting + container.ancestors + Object.ancestors).uniq
#slightly paraphrased

I guess the key point to understand is that for singleton methods,
container is the (static) module of class enclosing the singleton
method, NOT the singleton class that they affect.

Not sure I can follow you here. IMHO the key point is to understand
that it is a difference whether you open a scope (class, module) or
access the scope from the outside:

irb(main):001:0> module M
irb(main):002:1> class X; end
irb(main):003:1> O = Object.new
irb(main):004:1> end
=> #<Object:0x101792b4>
irb(main):005:0> def (M::O).x; X; end
=> nil
irb(main):006:0> M::O.x
NameError: uninitialized constant X
        from (irb):5:in `x'
        from (irb):6
        from /opt/bin/irb19:12:in `<main>'
irb(main):007:0> module M
irb(main):008:1> def O.y; X; end
irb(main):009:1> end
=> nil
irb(main):010:0> M::O.y
=> M::X
irb(main):011:0> def (M::O).x; M::X; end
=> nil
irb(main):012:0> M::O.x
=> M::X

Kind regards

robert

···

2010/6/7 Caleb Clausen <vikkous@gmail.com>:

On 6/7/10, Robert Klemme <shortcutter@googlemail.com> wrote:

2010/6/6 Intransition <transfire@gmail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thanks Robert and Caleb. At least it makes sense --even if it doesn't
make sense :wink:

Ah, but constant lookup is supposed to check the ancestors if the
constant is not found in the scope. M should be among the ancestors of
o's singleton class, shouldn't it? I would have expected this to work.
OTOH, constant lookup is confusing.

This way works:

module M
class X; end
end

o = Object.new # => #<Object:0x7fc61f1a1e58>

(class << o; self; end).class_eval{ include M } # => #<Object:0x7fc61f1a1e58>
#or o.extend M as well, presumably

class<<o
def x; X end
end

o.x #=>M::X

Seehttp://ruby.runpaint.org/variables#constantsin which the lookup
rules are summarized as:
(Module.nesting + container.ancestors + Object.ancestors).uniq
#slightly paraphrased

I guess the key point to understand is that for singleton methods,
container is the (static) module of class enclosing the singleton
method, NOT the singleton class that they affect.

I supposed, but that doesn't seem quite right, as the document pointed
out that "self.ancestors" should be looked up. Shouldn't that catch
the singleton class too?

Honestly. Something is not right if these are not the same:

  class << o
    def x; X end
  end

  def o.x; X; end

~trans

Sorry, I meant 'module or class', not 'module of class'. Basically,
I'm agreeing with what you said just above. It just took me a little
longer to get to the same point of understanding about constant lookup
that you were at. (Like I said: constant lookup is confusing.)

···

On 6/7/10, Robert Klemme <shortcutter@googlemail.com> wrote:

2010/6/7 Caleb Clausen <vikkous@gmail.com>:

Ah, but constant lookup is supposed to check the ancestors if the
constant is not found in the scope. M should be among the ancestors of
o's singleton class, shouldn't it?

It does but you are not in the scope of the singleton class. Rather
you are in the toplevel (or any other) scope when you do "def o.x; X;
end".

I guess the key point to understand is that for singleton methods,
container is the (static) module of class enclosing the singleton
method, NOT the singleton class that they affect.

Not sure I can follow you here. IMHO the key point is to understand
that it is a difference whether you open a scope (class, module) or
access the scope from the outside: