Ruby Method Search (Comparison with JavaScript)

I want to better understand how objects in Ruby have access methods defined in classes and modules. In particular, I want to compare and contrast it with JavaScript (with which I am more familiar).

In JavaScript, objects look for methods for the object itself, and if it cannot find it there, it will look for a method on the prototype object. This process will continue until achieved Object.prototype.

// JavaScript Example
var parent = {
  someMethod: function () {
    console.log( 'Inside Parent' );
  }
};

var child = Object.create( parent );
child.someMethod = function () {
  console.log( 'Inside Child' );
};

var obj1 = Object.create( child );
var obj2 = Object.create( child );

obj1.someMethod(); // 'Inside Child'
obj2.someMethod(); // 'Inside Child'

In the JavaScript example obj1, both obj2do not have functions someMethodfor the object itself. The key is to note that:

  • There's a copy of the function someMethodin the object childand the two obj1, and obj2is delegated object child.
  • , obj, obj2 someMethod .
  • child someMethod, parent.

Ruby:

# Ruby Example
class Parent
  def some_method
    put 'Inside Parent'
  end
end

class Child < Parent
  def some_method
    puts 'Inside Child'
  end
end

obj1 = Child.new
obj2 = Child.new

obj1.some_method  # 'Inside Child'
obj2.some_method  # 'Inside Child'

:

  • obj1 obj2 Ruby some_method? JavaScript, some_method ( Child)?
  • , Ruby, Ruby ?

, Ruby , , . , Ruby JavaScript, , , , , , BasicObject.

+4
3
  • obj1 obj2 Ruby some_method? JavaScript, some_method ( Child)?

. Ruby Language : " , ". . Ruby , , , , .

. , , . . (, , .)

  1. , Ruby, Ruby ?

, .

Ruby, , () . (, MRI, YARV, Rubinius, MRuby, Topaz, tinyrb, RubyGoLightly), , (, XRuby JRuby on Java, Ruby.NET IronRuby CLI, SmallRuby, smalltalk.rb, Alumina MagLev Smalltalk, MacRuby RubyMotion Objective-C/Cocoa, , ActionScript/Flash, BlueRuby SAP/ABAP, HotRuby Opal.rb ECMAScript)

, ?

, Ruby , , . , Ruby JavaScript, , , , , , BasicObject.

, , , , , (MRI, YARV, Rubinius, JRuby, IronRuby, MagLev, Topaz).

, , . String String 116. , String Ruby!

ruby -e 'p ObjectSpace.each_object(String).count'
# => 10013

, require - , ( ), 10000 . 100 String. .

! Ruby monkeypatch. , String? Ruby .

, String. , . , , : String, Comparable, Object, Kernel BasicObject. , require?

, , Ruby, . , ( -Ruby):

struct Object
  object_id: Id
  ivars: Dictionary<Symbol, *Object>
  class: *Class
end

, :

struct Module
  methods: Dictionary<Symbol, *Method>
  constants: Dictionary<Symbol, *Object>
  cvars: Dictionary<Symbol, *Object>
end

, :

struct Class
  methods: Dictionary<Symbol, *Method>
  constants: Dictionary<Symbol, *Object>
  cvars: Dictionary<Symbol, *Object>
  superclass: *Class
end

, Ruby class . , superclass , , . , method_missing , , , , ( , method_missing , , ).

, : ! . , , singleton :

struct Object
  object_id: Id
  ivars: Dictionary<Symbol, *Object>
  class: *Class
  singleton_class: Class
end

, .

? , , :

struct Module
  methods: Dictionary<Symbol, *Method>
  constants: Dictionary<Symbol, *Object>
  cvars: Dictionary<Symbol, *Object>
  mixins: List<*Module>
end

struct Class
  methods: Dictionary<Symbol, *Method>
  constants: Dictionary<Symbol, *Object>
  cvars: Dictionary<Symbol, *Object>
  superclass: *Class
  mixins: List<*Module>
end

: , , (es), , , "" " , , ( .., ), ".

? ! . - - , . , Ruby (, MRI, YARV), , , "" "" .

, , :

struct Object
  object_id: Id
  ivars: Dictionary<Symbol, *Object>
  class: *Class
  singleton_class: Class
end

, . . , , , :

struct Class
  methods: *Dictionary<Symbol, *Method>
  constants: *Dictionary<Symbol, *Object>
  cvars: *Dictionary<Symbol, *Object>
  superclass: *Class
  visible?: Bool
end

, singleton . mixin M C, Ruby M′, , cvar- mixin. mixin C, C mixin:

M′ = Class.new(
  methods = M->methods
  constants = M->constants
  cvars = M->cvars
  superclass = C->superclass
  visible? = false
)

C->superclass = *M'

, , , M ( ), , .

:

def lookup(meth, obj)
  c = obj->class

  until res = c->methods[meth]
    c = c->superclass
    raise MethodNotFound, meth if c.nil?
  end

  res
end

, .

, , , , , . Object#class Class#superclass? , ?

, Module#prepend . Refinements , Ruby .

+1

IRB , :

> obj1.method(:some_method)
=> #<Method: Child#some_method>
> obj1.method(:some_method).source_location
=> ["(irb)", 8]
> obj2.method(:some_method)
=> #<Method: Child#some_method>
> obj2.method(:some_method).source_location
=> ["(irb)", 8]

Ah ok, . , ...

> obj1.instance_eval do
>   def some_method
>     puts 'what is going on here?'
>   end
> end
=> nil
> obj1.some_method
what is going on here?
=> nil
> obj2.some_method
Inside Child
=> nil
> obj1.method(:some_method)
=> #<Method: #<Child:0x2b9c128>.some_method>
> obj1.method(:some_method).source_location
=> ["(irb)", 19]

, .

, , https://blog.jcoglan.com/2013/05/08/how-ruby-method-dispatch-works/

, . , - MRI, JRuby Rubinius, , Ruby .

+2

More food for thought

> obj1.instance_eval do
>  def some_method
>    puts "Inside Instance"
>    super
>  end
> end 
=> :some_method
Inside Instance
Inside Child
0
source

All Articles