2

I am currently practicing/learning singleton methods and singleton classes in Ruby, and I have come across a doubt. Given:

myobject = Object.new

Is there any difference between doing this:

def myobject.mymethod
end

and doing this:

class << myobject
 def mymethod
 end
end

If there is, when would we use one or the other? What are the implications?

Nobita
  • 23,519
  • 11
  • 58
  • 87

1 Answers1

2

Use ruby --dump ins to research the result, as follows:

1.

# test.rb
myobject = Object.new

def myobject.mymethod
end

executes ruby --dump ins test.rb

the output is:

D:\>ruby --dump ins test.rb
== disasm: <RubyVM::InstructionSequence:<main>@test.rb>=================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] myobject
0000 trace            1                                               (   1)
0002 getinlinecache   9, <ic:0>
0005 getconstant      :Object
0007 setinlinecache   <ic:0>
0009 send             :new, 0, nil, 0, <ic:1>
0015 setdynamic       myobject, 0
0018 trace            1                                               (   3)
0020 putspecialobject 1
0022 getdynamic       myobject, 0
0025 putobject        :mymethod
0027 putiseq          mymethod
0029 send             :"core#define_singleton_method", 3, nil, 0, <ic:2>
0035 leave
== disasm: <RubyVM::InstructionSequence:mymethod@test.rb>===============
0000 trace            8                                               (   3)
0002 putnil
0003 trace            16                                              (   4)
0005 leave

2.

# test.rb
myobject = Object.new

class << myobject
 def mymethod
 end
end

executes ruby --dump ins test.rb

the output is:

D:\>ruby --dump ins test.rb
== disasm: <RubyVM::InstructionSequence:<main>@test.rb>=================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] myobject
0000 trace            1                                               (   1)
0002 getinlinecache   9, <ic:0>
0005 getconstant      :Object
0007 setinlinecache   <ic:0>
0009 send             :new, 0, nil, 0, <ic:1>
0015 setdynamic       myobject, 0
0018 trace            1                                               (   3)
0020 getdynamic       myobject, 0
0023 putnil
0024 defineclass      :singletonclass, singletonclass, 1
0028 leave
== disasm: <RubyVM::InstructionSequence:singletonclass@test.rb>=========
0000 trace            2                                               (   3)
0002 trace            1                                               (   4)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject        :mymethod
0010 putiseq          mymethod
0012 send             :"core#define_method", 3, nil, 0, <ic:0>
0018 trace            4                                               (   6)
0020 leave                                                            (   4)
== disasm: <RubyVM::InstructionSequence:mymethod@test.rb>===============
0000 trace            8                                               (   4)
0002 putnil
0003 trace            16                                              (   5)
0005 leave

So def myobject.method the way is that first sends core#define_singleton_method message to the myobject , then, the core#define_singleton_method message's implementation gets the myobject's singleton class, and add method definition into the singleton class.

class << myobject the way is that first sends singletonclass message to the myobject , then, send core#define_method message to the myobject's singletonclass.

In practice,

if you want to define a some of singleton methods for the obj, use class << obj.

if you only define a singleton method for the obj, use def obj.method.

xzgyb
  • 452
  • 2
  • 7