Confused by nested functions

Hi,

Why does the first one work but not the second one?

irb(main):001:0> class Test; end
=> nil
irb(main):002:0> def Test.boo; def moo; puts "moo"; end; end
=> nil
irb(main):003:0> Test.boo.moo
moo
=> nil

irb(main):001:0> class Test; def Test.boo; def moo; puts "moo"; end; end; end
=> nil
irb(main):002:0> Test.boo.moo
NoMethodError: undefined method `moo' for nil:NilClass
        from (irb):2

Thanks,
Navin.

Navindra Umanee wrote:

Why does the first one work but not the second one?

Ruby doesn't really have nested functions, and "def" is executable code just like anything else. So a nested "def" doesn't define its function until the function containing it is executed.

(Caught me out too.)

mathew

···

--
<URL:http://www.pobox.com/~meta/&gt;
          WE HAVE TACOS

Navindra Umanee wrote:

Why does the first one work but not the second one?

As mathew said, def is just a command to define a method, it runs when the interpreter gets to that line. What makes the first one work and the second one not, however, is a matter of scope. When 'def' is called, it defines a method in a certain place. That place is determined by what 'class' or 'module' it's in. So class Test; def foo; end end defines a method on Test objects.

#1: def moo; puts 'moo' end is *not inside a 'class' or 'module' block*. This is important. You may be defining a class method boo on Test (well, a singleton method on the Test object), but your @@class_variables won't actually be class variables of Test, because it's outside the class block. It's out in the wild. Here's what the PickAxe2 (p. 346) has to say about that:

"Outside a class or module definition, a definition with an unadorned method name is added as a private method to class Object, and hence may be called in any context without an explicit receiver."

So what's happening here?

Test.boo calls the Test.boo method you defined, which defines a private method moo on Object. The 'def' keyword, as you've seen returns nil. So Test.boo returns nil. Test.boo.moo tries to invoke the moo method on the nil object. Since nil.is_a? Object, it has the moo method that you just defined.

(I'm thinking the PickAxe may be wrong? about the private thing since you can call #moo with an explicit receiver -- sounds more like public. Can somebody explain?)

#2: When Test.boo is called, moo is defined as an instance method on Test. Test.boo returns nil, as before, but nil is not a Test object, so the moo method does not exist.

···

---

So... The best way to do what you actually want depends on what you actually want. Are you just trying to group a bunch of similar methods inside a subcomponent of Test, or do you want the Test.boo.moo method to be dynamically generated based on what Test.boo does? If the latter, then keep in mind that every method call returns an Object. What you want to do is make Test.boo return an Object that has a moo method on it.

Devin

Hi --

Navindra Umanee wrote:

Why does the first one work but not the second one?

As mathew said, def is just a command to define a method, it runs when the interpreter gets to that line. What makes the first one work and the second one not, however, is a matter of scope. When 'def' is called, it defines a method in a certain place. That place is determined by what 'class' or 'module' it's in. So class Test; def foo; end end defines a method on Test objects.

#1: def moo; puts 'moo' end is *not inside a 'class' or 'module' block*. This is important. You may be defining a class method boo on Test (well, a singleton method on the Test object), but your @@class_variables won't actually be class variables of Test, because it's outside the class block. It's out in the wild. Here's what the PickAxe2 (p. 346) has to say about that:

"Outside a class or module definition, a definition with an unadorned method name is added as a private method to class Object, and hence may be called in any context without an explicit receiver."

So what's happening here?

Test.boo calls the Test.boo method you defined, which defines a private method moo on Object. The 'def' keyword, as you've seen returns nil. So Test.boo returns nil. Test.boo.moo tries to invoke the moo method on the nil object. Since nil.is_a? Object, it has the moo method that you just defined.

(I'm thinking the PickAxe may be wrong? about the private thing since you can call #moo with an explicit receiver -- sounds more like public. Can somebody explain?)

I think the private thing depends on lexical scope. Since the nested
definition of moo is not lexically a top-level definition, it isn't
privatized.

#2: When Test.boo is called, moo is defined as an instance method on Test. Test.boo returns nil, as before, but nil is not a Test object, so the moo method does not exist.

What I find interesting is this:

   class D
     def D.boo
       def moo
         puts "moo"
       end
     end

     def bee
       def mee
         puts "mee"
       end
     end
   end

   D.boo
   d = D.new
   d.bee

   p D.instance_methods.sort # includes both moo and mee

Nesting a definition inside a class method, and nesting a definition
inside an instance method, have exactly the same effect: an instance
method is added to the class. In one case, this means "self"; in the
other, it means "self.class". I'm not sure why it works this way.
Maybe the real rule is "one lexical layer up", which would take both
to the class-definition scope that surrounds them.

David

···

On Sun, 11 Sep 2005, Devin Mullins wrote:

--
David A. Black
dblack@wobblini.net

So... The best way to do what you actually want depends on what you
actually want.

Thanks for the careful explanation, Devin.

Are you just trying to group a bunch of similar methods
inside a subcomponent of Test, or do you want the Test.boo.moo method to
be dynamically generated based on what Test.boo does? If the latter,

I was trying to dynamically generate methods within a namespace -- so
essentially the first. For example, I want to generate:

Site.tables.table1()
Site.tables.table2()
Site.pages.page1()
Site.pages.page2()

Except with better names, of course. :slight_smile:

I guess I should return an Object with the methods I want.

Thanks,
Navin.

···

Devin Mullins <twifkak@comcast.net> wrote:

Yo --

David A. Black wrote:

(I'm thinking the PickAxe may be wrong? about the private thing since you can call #moo with an explicit receiver -- sounds more like public. Can somebody explain?)

I think the private thing depends on lexical scope. Since the nested
definition of moo is not lexically a top-level definition, it isn't
privatized.

I'm not sure what you mean. Seems lexically top-level to me -- it's not inside a class or module block. That it's inside a method doesn't seem to make a difference:

irb(main):001:0> def moo; puts 'moo' end
=> nil
irb(main):002:0> nil.moo
moo
=> nil

You know, if I weren't so !#%@#ing afraid of just reading the @#%#@ing source code, I'd've had this question answered by now.

#2: When Test.boo is called, moo is defined as an instance method on Test. Test.boo returns nil, as before, but nil is not a Test object, so the moo method does not exist.

What I find interesting is this:

Nesting a definition inside a class method, and nesting a definition
inside an instance method, have exactly the same effect: an instance
method is added to the class. In one case, this means "self"; in the
other, it means "self.class". I'm not sure why it works this way.

Maybe the real rule is "one lexical layer up", which would take both
to the class-definition scope that surrounds them.

Precisely. It works like class variables -- it depends solely on the *lexical* scope of the method definition. You could have written:

class D
  def bee
    def mee
      puts "mee"
    end
  end
end
module SomeOtherModule
  def D.boo
    def moo
      puts "moo"
    end
  end
end

  D.boo
  d = D.new
  d.bee

  p (D.instance_methods - D.superclass.instance_methods) # includes only mee & bee
  p SomeOtherModule.instance_methods #includes only moo

And yes, it is interesting. :slight_smile:

Devin

···

On Sun, 11 Sep 2005, Devin Mullins wrote:

Yo --

David A. Black wrote:

>
>> (I'm thinking the PickAxe may be wrong? about the private thing since
>> you can call #moo with an explicit receiver -- sounds more like
>> public. Can somebody explain?)
>
>
> I think the private thing depends on lexical scope. Since the nested
> definition of moo is not lexically a top-level definition, it isn't
> privatized.

I'm not sure what you mean. Seems lexically top-level to me -- it's not
inside a class or module block. That it's inside a method doesn't seem
to make a difference:

irb(main):001:0> def moo; puts 'moo' end
=> nil
irb(main):002:0> nil.moo
moo
=> nil

Just a quick note: beware of IRB. when it comes to method and variable
visibility, it doesn't always behave the same as in normal code:

mark@eMac% irb
ruby 1.8.2 (2004-12-25) on powerpc-darwin8.0
Welcome to Interactive Ruby
def foo() :foo end
    ==>nil
nil.foo
    ==>:foo
mark@eMac% ruby <<EOT

def foo() :foo end
p nil.foo
EOT

-:2: private method `foo' called for nil:NilClass (NoMethodError)
mark@eMac%

···

On 9/11/05, Devin Mullins <twifkak@comcast.net> wrote:

> On Sun, 11 Sep 2005, Devin Mullins wrote:

You know, if I weren't so !#%@#ing afraid of just reading the @#%#@ing
source code, I'd've had this question answered by now.

>> #2: When Test.boo is called, moo is defined as an instance method on
>> Test. Test.boo returns nil, as before, but nil is not a Test object,
>> so the moo method does not exist.
>
>
> What I find interesting is this:
>
> Nesting a definition inside a class method, and nesting a definition
> inside an instance method, have exactly the same effect: an instance
> method is added to the class. In one case, this means "self"; in the
> other, it means "self.class". I'm not sure why it works this way.

> Maybe the real rule is "one lexical layer up", which would take both
> to the class-definition scope that surrounds them.

Precisely. It works like class variables -- it depends solely on the
*lexical* scope of the method definition. You could have written:

class D
  def bee
    def mee
      puts "mee"
    end
  end
end
module SomeOtherModule
  def D.boo
    def moo
      puts "moo"
    end
  end
end

  D.boo
  d = D.new
  d.bee

  p (D.instance_methods - D.superclass.instance_methods) # includes only
mee & bee
  p SomeOtherModule.instance_methods #includes only moo

And yes, it is interesting. :slight_smile:

Devin

Hi --

Yo --

David A. Black wrote:

(I'm thinking the PickAxe may be wrong? about the private thing since you can call #moo with an explicit receiver -- sounds more like public. Can somebody explain?)

I think the private thing depends on lexical scope. Since the nested
definition of moo is not lexically a top-level definition, it isn't
privatized.

I'm not sure what you mean. Seems lexically top-level to me -- it's not inside a class or module block. That it's inside a method doesn't seem to make a difference:

irb(main):001:0> def moo; puts 'moo' end
=> nil
irb(main):002:0> nil.moo
moo
=> nil

As Mark says, that's an IRB thing. In Ruby itself:

   $ ruby -e 'def x; end; nil.x'
   -e:1: private method `x' called for nil:NilClass (NoMethodError)

And, just for reference:

   $ ruby -e 'def x; def y; p 1; end; end; x; nil.y'
   1

Since def's start a new local scope, I think it's reasonable to
describe "def y" as not being lexically top-level (which I wouldn't if
it were, say, inside an if statement rather than another def). We can
in any case call it "outermost scope". My interpretation is that only
methods whose definitions start in the outermost scope are made into
private methods of Object.

David

···

On Mon, 12 Sep 2005, Devin Mullins wrote:

On Sun, 11 Sep 2005, Devin Mullins wrote:

--
David A. Black
dblack@wobblini.net

Blrgh! Thanks, Mark & David. I have been schooled.

My interpretation is that only
methods whose definitions start in the outermost scope are made into
private methods of Object.

Indeed, that's my impression now, too. I also know now that the magical top-level Object does not have a singleton class:

a = ""
class << a; def foo; def y; puts 'yo'; end end end
a.foo
a.y
"hello".y
__END__
yo
-:5: undefined method `y' for "hello":String (NoMethodError)

or, well, act like it.

Devin

David A. Black wrote:

···

irb(main):001:0> def moo; puts 'moo' end
=> nil
irb(main):002:0> nil.moo
moo
=> nil

As Mark says, that's an IRB thing. In Ruby itself:

  $ ruby -e 'def x; end; nil.x'
  -e:1: private method `x' called for nil:NilClass (NoMethodError)

And, just for reference:

  $ ruby -e 'def x; def y; p 1; end; end; x; nil.y'
  1

Since def's start a new local scope, I think it's reasonable to
describe "def y" as not being lexically top-level (which I wouldn't if
it were, say, inside an if statement rather than another def). We can
in any case call it "outermost scope". My interpretation is that only
methods whose definitions start in the outermost scope are made into
private methods of Object.

David

Hi --

···

On Tue, 13 Sep 2005, Devin Mullins wrote:

Blrgh! Thanks, Mark & David. I have been schooled.

My interpretation is that only
methods whose definitions start in the outermost scope are made into
private methods of Object.

Indeed, that's my impression now, too. I also know now that the magical top-level Object does not have a singleton class:

a = ""
class << a; def foo; def y; puts 'yo'; end end end
a.foo
a.y
"hello".y
__END__
yo
-:5: undefined method `y' for "hello":String (NoMethodError)

or, well, act like it.

You're not accessing the top-level object's singleton class there,
though. What you'd want would be:

   $ ruby -e 'class << self; def x; p 1; end; end; x'
   1

David

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

You're not accessing the top-level object's singleton class there,
though. What you'd want would be:

  $ ruby -e 'class << self; def x; p 1; end; end; x'
  1

I, uh... must be tired. Yeah, that's it. I'm going to shut up now. :slight_smile:

Devin
confused by the sound of his own voice, apparently...