aoiee
aoiee

Reputation: 355

Ruby method scope?

In the following example:

Main.rb

def main
  obj = ExampleClass.new
  def multiply(a, b, c, d)
    return a * b * c * d
  end
  puts obj.multiply(1, 2, 3, 4) # this prints 24
end
main

ExampleClass.rb

class ExampleClass
  def initialize

  end
end

Why is the multiply method now part of the obj instance? (the main method is not part of the ExampleClass definition)

Upvotes: 2

Views: 287

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369428

Methods defined at script scope become private instance methods of Object. (Except in IRb, where they become public instance methods of Object.)

So, main is a private instance method of Object.

Method definitions inside methods do not create nested methods, i.e. multiply is not nested in main. Rather, each time you call main, you will create a new method called multiply as an instance method of Object. And for some reason that is not quite clear to me, it ends up as a public method.

So, what happens is the following:

  1. you define main as a private instance method of Object
  2. you call main, which will in turn define multiply as a public instance method of Object
  3. you call multiply, which works because obj is an instance of ExampleClass which is a subclass of Object, which has your multiply method

Upvotes: 2

Radix
Radix

Reputation: 2747

The code written without additional class .. end, module .. end enclosures is executed directly, step by step, in context of special main object. This object can be referenced using:

2.2.2 :001 > self
# => main 

Methods defined without additional classes/modules are defined as private methods of the main object, and, consequently, as private methods of almost any other object in Ruby:

2.2.2 :002 > def foo
2.2.2 :003?>   42
2.2.2 :004?> end
# => :foo 
2.2.2 :005 > foo
# => 42 
2.2.2 :006 > [].foo
# => NoMethodError: private method `foo' called for []:Array
2.2.2 :007 > [].send :foo
# => 42

Thus, in your code, main method (or it can any other method) is in the context of main object and so multiply method can be called from either ExampleClass.new or Array.new or from any other class.

Source: Wikipedia

UPDATE

Few notes from engineersmnky's comment.

  1. This is not a private method in main but rather a private method of BasicObject (in 2.0-2.2).

  2. As of 2.3 (and in 1.9.3) this method is not even privatized.

  3. It need not be an instance of the class e.g. Class.new as the class itself will also have this method defined e.g. BasicObject.foo

Upvotes: 3

rodsoars
rodsoars

Reputation: 401

Maybe it's because both the variable obj and the context where the method multiply was defined have Object as parent/ancestor.

If you call obj.class you will get ExampleClass < Object. Supposing you are in the console, if you call self.class, you will get Object < BasicObject. So, in your code, you have defined a method multiply for Object class. That's why multiply is part of obj instance.

Upvotes: 2

Related Questions