1

If I call method a once, it calls the outside method only. When I call it the second time, it calls the inside method.

class A
  def a
    puts "outside method"
    def a
      puts "inside method"
    end
  end
end

A.new.a # => outside method
A.new.a # => inside method 

Can you explain how it works?

ozil
  • 6,930
  • 9
  • 33
  • 56
Narasimha Reddy - Geeker
  • 3,510
  • 2
  • 18
  • 23

3 Answers3

5

The reason is that nested method are always applied to the containing class. The second method will be added to the A class, since it's the containing class of the first method.

However, it will be added only when its body code is evaluated, and it is evaluated when you first call the outer method.

class Test
  def foo
    puts "outside method"
    def bar
      puts "inside method"
    end
  end
end

test = Test.new
test.methods - Object.methods # => [:foo]
test.foo
test.methods - Object.methods # => [:foo, :bar]

In ruby, defining a method with the same name within a class twice will override the first version.

class Test
  def foo
    "first version"
  end

  def foo
    "second version"
  end
end

test = Test.new
test.foo # => "second version"

Therefore, after the first execution of A#a, the inner implementation remains.

sawa
  • 165,429
  • 45
  • 277
  • 381
ndnenkov
  • 35,425
  • 9
  • 72
  • 104
  • Isn't it just bad practice to do such a thing? – Charles Sep 28 '15 at 13:32
  • @c650, mostly - yes. There certainly are applications, but you shouldn't do this in your everyday code if you don't have a very compelling reason for it. – ndnenkov Sep 28 '15 at 13:35
  • Thought so. Especially the same name... But I guess it's practical if you want a certain version of a method to only be runnable once. – Charles Sep 28 '15 at 13:58
2

There is no inside or outside method here. There are no nested methods in Ruby.

What you have is a method, which, when you call it, will define a method, which happens to overwrite the method. Note the warning!

A.new.a
# outside method
# warning: method redefined; discarding old a
# warning: previous definition of a was here

A.new.a
# inside method

Never ignore warnings! Sometimes they are wrong, but usually, they are telling you something. You should always examine them.

Community
  • 1
  • 1
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0

Nothing special going on. Follow the method definitions.

  • Before calling A.new.a: The class body is executed.
    • Define a as the outer a.
  • First call of A.new.a: The method body of the outer a is executed.
    • Print "outside method" and then
    • Define a as the inner a.
  • Second call of A.new.a: The method body of the inner a is executed.
    • Print "inside method".
sawa
  • 165,429
  • 45
  • 277
  • 381