Why can't I get on Top?

T

Trans

More Toplevel blow:

$toplevel = self
module Test
def self.included( base )
p base == $toplevel
end
end
include Test

Produces:

false

:-(

T.
 
M

MonkeeSage

Trans said:
Produces:

false

That's correct. In that case self is an *instance* of Object...

module Test
def test
puts 'hi'
end
end
class << self
include Test
end
test

....but Module#included tells you the module or class of the including
scope; it doesn't pass the instance itself.

Regards,
Jordan
 
D

dblack

Hi --

That's correct. In that case self is an *instance* of Object...

module Test
def test
puts 'hi'
end
end
class << self
include Test
end
test

...but Module#included tells you the module or class of the including
scope; it doesn't pass the instance itself.

Yes it does: the instance itself *is* a Module (or Class) :) There's
no translation or looking up necessary:

class C
include M # the method "include" is called on the object C
end

The top level is a bit anomalous: 'self' is not a Module or Class, but
it does some proxying for Object. So if you do:

include M

at the top level, it's as if you'd done:

class Object
include M
end


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

MonkeeSage

The top level is a bit anomalous: 'self' is not a Module or Class, but
it does some proxying for Object. So if you do:

include M

at the top level, it's as if you'd done:

class Object
include M
end

That's what I was trying to say. ;)

But main is an *instance* of Object, isn't it? At least, it acts like
one. Thus singleton methods:

class << self
include Test
end

And class membership:

p self.class

Regards,
Jordan
 
T

Trans

The top level is a bit anomalous: 'self' is not a Module or Class, but
it does some proxying for Object. So if you do:

Right. So how does one catch if a module is included at the toplevel
then?
But main is an *instance* of Object, isn't it? At least, it acts like
one. Thus singleton methods:

Yes, but so is everything.


I really wish someone would tell me what's wrong with a self extended
module for toplevel instead of this silly proxy of Object.

T.
 
M

MonkeeSage

Trans said:
Yes, but so is everything.

Hmmm...I'm not the sharpest tool in the shed, but I don't think that is
correct. There are first-order objects like classes and modules.
Normally #included gets the class or module object itself, not an
instance. At least that's how I've always thought it worked.

module Test
def self.included(base)
p base.instance_of?(C) # => false
base.module_eval { # <- extends the actual class, not an instance
def m
puts 'Howdy do'
end
}
end
end
class C
include Test
end
C.new.m

Regards,
Jordan
 
T

Timothy Goddard

The base level in Ruby runs in the context of an instance of Object.
When you add base level methods you're actually adding those methods to
the eigenclass of the main object. The main object in essence is an
instance of its eigenclass and the eigenclass is a subclass of the
Object class. You can do this with any Ruby object (except Fixnums,
which is an annoying inconsistency):

irb(main):010:0> a = "Frog"
=> "Frog"

irb(main):011:0> def a.double
irb(main):012:1> self * 2
irb(main):013:1> end
=> nil

irb(main):014:0> a.double
=> "FrogFrog"

irb(main):015:0> b = "Camel"
=> "Camel"

irb(main):016:0> b.double
NoMethodError: undefined method `double' for "Camel":String
from (irb):16
from :0

Note that the original String class isn't affected - the method has
been added to the eigenclass of object a.
 
D

dblack

Hi --

The base level in Ruby runs in the context of an instance of Object.
When you add base level methods you're actually adding those methods to
the eigenclass of the main object. The main object in essence is an
instance of its eigenclass and the eigenclass is a subclass of the
Object class. You can do this with any Ruby object (except Fixnums,
which is an annoying inconsistency):

The singleton class/object relationship isn't quite an instance one;
it's a little more "phantom"-like. It doesn't add a real level to the
"family tree"; an object is still an instance of the thing it was an
instance of before:

class C; end
class D < C; end

d = D.new
sing = class << d; self; end

p D.new.instance_of?(C) # false
p D.new.instance_of?(D) # true
p D.new.instance_of?(sing) # false

So thinking of the singleton class as a subclass of the object's class
might be a little misleading, since the object still relates to its
"birth class" at only one level of remove.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
D

dblack

Hi --

Of course, but what I am puzzeled about is, why you use #instance_of?, well
not really, because that was how the argument began.
As a matter of fact let me be more humble ;)
I am afraid I missed something basic in the discussion, because to my
understanding #instance_of? is irrelevant and #is_a?
is what we are interested in, no? (obviously no ;).

I was responding to Timothy's description of the default object main
as an instance of its singleton class. My point was that the
relationship between an object and its singleton class is not actually
defined by Ruby as a class-instance relationship, though of course it
is very similar to such a relationship in many ways.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
T

Trans

Jeffrey said:
module Test
def self.included( base )
p base == $toplevel
end
end

class << self

# $toplevel has to be set in here,
# where it can really refer to the
# including object.

$toplevel = self
include Test
end

In your example you are controlling the inclusion from the start.
That's missing the point. The #included callback catches the inclusion
of a module and _reacts_ to that. The module is a resuable lib that an
end-user/programmer may well include at the toplevel and the module
should just work. Otherwise one has to document: "IMPORTANT: don't
include at toplevel, It won't work...."

But you also may not realize that methods defined at the toplevel do
not go to the singleton. They go to Object itself. So really your
example should be:

class Object
$toplevel = self
include Test
end

But you are getting a false positive, since:

module NotTheTopLevel
$toplevel = self
include Test
end

works too.

T.
 
T

Trans

Timothy said:
The base level in Ruby runs in the context of an instance of Object.
When you add base level methods you're actually adding those methods to
the eigenclass of the main object.

That's not correct. The methods are being added to Object itself. Main
is just a proxy. The methods is has related to defining and looking up
methods just reroute to Object.

def x; end
p Object.private_instance_methods(false)
=> ['initialize', 'x']

To add to the toplevel pot:

def x; end
respond_to?:)x)
=> false

(I know, b/c it's private method, but still.)

T.
 
L

Logan Capaldo

More Toplevel blow:

$toplevel = self
module Test
def self.included( base )
p base == $toplevel
end
end
include Test

Produces:

false

:-(
I wonder if the powers that be would consider adding some additional
hooks if they don;t want to make the top-level an extended self module.

(e.g:

alias toplevel_include include
def include(mod)
toplevel_include( mod )
mod.included( self )
end

I don't really like that actually. Trans, consider my vote added in
favor to "Make the toplevel a self-extended module". It just seems so
much more useful and cleaner without this silly proxying.
 
M

MonkeeSage

Hi Trans,

How about a workaround for now? Something like:

class << self
def include(mod)
self.extend(mod)
if in_toplevel?
p 'Do NOT use me from toplevel'
end
end
end

module NoTopLevel
def in_toplevel?
self.to_s == 'main'
end
end

include NoTopLevel

Regards,
Jordan
 
T

Trans

MonkeeSage said:
Hi Trans,

How about a workaround for now? Something like:

class << self
def include(mod)
self.extend(mod)
if in_toplevel?
p 'Do NOT use me from toplevel'
end
end
end

module NoTopLevel
def in_toplevel?
self.to_s == 'main'
end
end

include NoTopLevel

Well, let me show you what I'm actually doing:

module Taskable
def self.included( base )
if base.toplevel?
require 'main_as_module.rb'
end
end
end

main_as_module.rb is actually a bit of code that will add every module
method there is to toplevel (ie. main). So you see I'm actually trying
to selectively mitigate the issue were talking about. I could just
require this lib no matter what and be done with it, but I thought it
would be better if I only included it if it is needed --no sense in
loading code that's not used. But it looks like I don't have much
choice. However, I did manage this work-around:

module Taskable
def self.included( base )
if base == Object
require 'main_as_module.rb'
end
end
end

That catches it, although it also catches when Taskable is included in
Object too. But that's only one exception that won't cause any harm, so
it's an accecptable work around.

T.
 
M

MonkeeSage

Trans said:
That catches it, although it also catches when Taskable is included in
Object too. But that's only one exception that won't cause any harm, so
it's an accecptable work around.

Right on. I just realized that my last suggestion was retarded anyhow,
since in_toplevel? *had* to be true, always, since I was only
overriding #include as a singleton method of the main instance. Doh
(guess I'm still not the sharpest tool!).

Regards,
Jordan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,214
Messages
2,571,112
Members
47,704
Latest member
DavidSuita

Latest Threads

Top