Using a module at the toplevel doesn't work

Hi,

···

In message "Re: using a module at the toplevel doesn't work" on Tue, 22 Aug 2006 14:05:06 +0900, "Trans" <transfire@gmail.com> writes:

As you can see my particlar 'test' example will cause an infinite loop
because the toplevel definition is being added to all objects. :frowning:

But they are private by default, so that 1.9 send will call
method_missing if you specify the explicit receiver.

              matz.

Logan Capaldo wrote:

You are over simplifying Trans.'s problem.

Yea Pit, why are you doing that? :wink:

He wants dynamic generated
methods scoped to a module, or optionally scoped to the top level.
You can't use #define_method at the top level because instances don't
respond to it. You can't use the toplevel singleton class as I
suggested because a) it's a pain in the neck and b) it doesn't
inherit the right way.

Trans, what about:

# Warning evilness ensuing:

def main.define_method(*args, &block)
   Kernel.module_eval{ define_method(*args, &block) }
end

That's basically what I ended up doing:

  def define_method( meth, &block )
    Object.class_eval do
      define_method( meth, &block )
      private meth
    end
  end

  def ancestors
    Object.ancestors
  end

But as I was saying about the instance variables, it not quite that
simple. I still had to build exceptions into the module code. I just
tried to factor these down to the fewest points of departure as
possible. So I end up with a few areas like this:

  $main = self

  def instance_task_table
    if self == $main
      Object.instance_task_table
    else
      @instance_task_table ||= {}
    end
  end

and

  cont = (self == $main ? Object : self )

Certainly not simple. But so far it appears to be working. I just hope
I've got all the namespace dicing covered.

Thanks,
T.

Yukihiro Matsumoto wrote:

Hi,

>As you can see my particlar 'test' example will cause an infinite loop
>because the toplevel definition is being added to all objects. :frowning:

But they are private by default, so that 1.9 send will call
method_missing if you specify the explicit receiver.

Ah, okay so fixing my toplevel #define_method to privatize the method
should do the trick, at least in my case, I see. Thanks. Of course,
just my luck, I also need 1.9's #send that doesn't invoke private
methods now! :wink: How do I get around that in 1.8 again?

So #private saves the situation. Hmm... Still, the subtleties involved
here make me wonder, is it worth it? Has the embuing of toplevel
methods throughout all objects proven of significant worth? I knwo I
have never intentially created a toplevel method with the intended
effect of adding it to all objects. And Mathew makes another good case.

Thanks,
T.

···

In message "Re: using a module at the toplevel doesn't work" > on Tue, 22 Aug 2006 14:05:06 +0900, "Trans" <transfire@gmail.com> writes:

Trans wrote:

How do I get around that in 1.8 again?

To answer my own question:

        eval %{ Script.#{type}(*args, &data) }

T.

For his case, replace do_test as

   def self.do_test
     self.test
   end
              matz.

···

In message "Re: using a module at the toplevel doesn't work" on Tue, 22 Aug 2006 22:20:05 +0900, "Trans" <transfire@gmail.com> writes:

And Mathew makes another good case.

Yukihiro Matsumoto wrote:

>And Mathew makes another good case.

For his case, replace do_test as

   def self.do_test
     self.test
   end

Almost. But that's sort of reverse the situation. Will we have to add
'self.' to every call b/c there's the chance someone will define a
toplevel method when using our libs?

I think the question stands: of what significant value come from having
the toplevel add it's methods to Object?

If we have to know these subtle tricks to avoid possible gotchas, don't
you think it should be worth the effort? I don't see how it is. I don't
think a good coder is even going to utilze the fact that toplevel
methods embue all objects in the first place.

T.

···

In message "Re: using a module at the toplevel doesn't work" > on Tue, 22 Aug 2006 22:20:05 +0900, "Trans" <transfire@gmail.com> writes:

Almost. But that's sort of reverse the situation. Will we have to add
'self.' to every call b/c there's the chance someone will define a
toplevel method when using our libs?

You won't need to add self to every call, only to calls which may end up in method_missing. If the method is guaranteed to exist in the object or one of its ancestors self is not necessary to ensure the expected method is called. Expecting calls to self to end up in method_missing seems like a pretty specialized case...

Matthew

Matthew Johnson wrote:

> Almost. But that's sort of reverse the situation. Will we have to add
> 'self.' to every call b/c there's the chance someone will define a
> toplevel method when using our libs?

You won't need to add self to every call, only to calls which may end
up in method_missing. If the method is guaranteed to exist in the
object or one of its ancestors self is not necessary to ensure the
expected method is called. Expecting calls to self to end up in
method_missing seems like a pretty specialized case...

Sure. All of this is a specialized case. It's a specialized case to use
the toplevel to purposefully add methods to Object. Toplevel methods
aren't that common in the first place, except in one-off scripts. But
if you actaully are utilizng the toplevel, for instance in mycase where
end-users are writting mini task scripts, then these specialized cases
come to bare strongly.

So far his is what I have had to deal with:

  1. Manually add #define_method, #ancestors, &c. to proxy to Object
class.
  2. Be careful b/c Toplevel and Object class 'self' can get mixed-up.
  3. Avoid using #send if you're utilizing method_missing (util 1.9)
  4. Add 'self.' prefix to internal methods if purposefully invoking
method_missing.

And I wouldn't be suprised if their are others.

So it's not that this is a huge issue, obviously. But why have these
issues at all if it's completely and easily avoidable? Using a self
extended module (Main) for the toplevel avoids all of this. And if, for
some reason, one needs to add their top level methods to all objects,
'class Object; include Main; end' is a very simple solution.

T.

s/their/there/

My grandmother hates it when I do that :wink:

T.

Also, irb screws it up:

  irb(main):001:0> def x ; "x" ; end
  => nil
  irb(main):002:0> Object.private_instance_methods(false).sort
  => ["initialize", "irb_binding"]
  irb(main):003:0> Object.public_instance_methods(false).sort
  => ["x"]

T.

Hi,

···

In message "Re: using a module at the toplevel doesn't work" on Thu, 24 Aug 2006 07:50:13 +0900, "Trans" <transfire@gmail.com> writes:

Also, irb screws it up:

Yes, it is a irb's known bug.

              matz.