ruby closures, how are they possible?

115
Ruby closures How are they possible? Carlos Alonso Software Engineer @calonso

Upload: carlos-alonso-perez

Post on 13-Jan-2017

46 views

Category:

Engineering


4 download

TRANSCRIPT

Page 1: Ruby closures, how are they possible?

Ruby closuresHow are they possible?

Carlos Alonso Software Engineer

@calonso

Page 2: Ruby closures, how are they possible?

A story about curiosity…

Page 3: Ruby closures, how are they possible?

I am curious

Page 4: Ruby closures, how are they possible?
Page 5: Ruby closures, how are they possible?
Page 6: Ruby closures, how are they possible?
Page 7: Ruby closures, how are they possible?

def greet str = “hello” lambda do puts str end end f = greet f.call # => hello

Page 8: Ruby closures, how are they possible?

def greet str = “hello” lambda do puts str end end f = greet f.call # => hello

Page 9: Ruby closures, how are they possible?

def greet str = “hello” lambda do puts str end end f = greet f.call # => hello

This talk!

Page 10: Ruby closures, how are they possible?

Some examples…

Page 11: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

Page 12: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

NameError: Undefined `a’

Page 13: Ruby closures, how are they possible?

def run_block yield end

a = 1 run_block { a + 1 }

Page 14: Ruby closures, how are they possible?

def run_block yield end

a = 1 run_block { a + 1 }

2

Page 15: Ruby closures, how are they possible?

def run_block a = 1 yield end

run_block { a + 1 }

Page 16: Ruby closures, how are they possible?

def run_block a = 1 yield end

run_block { a + 1 }

NameError: Undefined `a’

Page 17: Ruby closures, how are they possible?

def run_block a = 100 yield end

a = 1 run_block { a + 1 }

Page 18: Ruby closures, how are they possible?

def run_block a = 100 yield end

a = 1 run_block { a + 1 }

2

Page 19: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

Page 20: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

3

Page 21: Ruby closures, how are they possible?
Page 22: Ruby closures, how are they possible?

What is a closure?

A lambda expression +

an environment to run it

Page 23: Ruby closures, how are they possible?

Blocks refer to variables declared in the scope where they were defined,

not where they are executed.

Lexical scope

Page 24: Ruby closures, how are they possible?

Ruby uses lexical scope. Let’s see this scopes!!

Page 25: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

Page 26: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

top-level a = 1 sum = …

Page 27: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

top-level a = 1 sum = …

sum a??

Page 28: Ruby closures, how are they possible?

a = 1 def sum a + 1 end sum

top-level a = 1 sum = …

sum a??

NameError: Undefined `a’

Page 29: Ruby closures, how are they possible?

def run_block(&block) yield end

a = 1 run_block { a + 1 }

Page 30: Ruby closures, how are they possible?

def run_block(&block) yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

Page 31: Ruby closures, how are they possible?

def run_block(&block) yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1 run_block

block

Page 32: Ruby closures, how are they possible?

def run_block(&block) yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

in-block a

run_block block

Page 33: Ruby closures, how are they possible?

def run_block(&block) yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

in-block a

run_block block

2

Page 34: Ruby closures, how are they possible?

def run_block(&block) a = 1 yield end

run_block { a + 1 }

Page 35: Ruby closures, how are they possible?

def run_block(&block) a = 1 yield end

run_block { a + 1 }

top-level run_block = …

Page 36: Ruby closures, how are they possible?

def run_block(&block) a = 1 yield end

run_block { a + 1 }

top-level run_block = …

run_block a = 1 block

Page 37: Ruby closures, how are they possible?

def run_block(&block) a = 1 yield end

run_block { a + 1 }

top-level run_block = …

in-block a??

run_block a = 1 block

Page 38: Ruby closures, how are they possible?

def run_block(&block) a = 1 yield end

run_block { a + 1 }

top-level run_block = …

in-block a??

run_block a = 1 block

NameError: Undefined `a’

Page 39: Ruby closures, how are they possible?

def run_block(&block) a = 100 yield end

a = 1 run_block { a + 1 }

Page 40: Ruby closures, how are they possible?

def run_block(&block) a = 100 yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

Page 41: Ruby closures, how are they possible?

def run_block(&block) a = 100 yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1 run_block

a = 100 block

Page 42: Ruby closures, how are they possible?

def run_block(&block) a = 100 yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

in-block a

run_block a = 100 block

Page 43: Ruby closures, how are they possible?

def run_block(&block) a = 100 yield end

a = 1 run_block { a + 1 }

top-level run_block = … a = 1

in-block a

run_block a = 100 block

2

Page 44: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

Page 45: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

top-level a = 2 sum…

Page 46: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

top-level a = 2 sum…

in-lambda a

Page 47: Ruby closures, how are they possible?

a = 1 sum = lambda do a + 1 end a = 2 sum.call

top-level a = 2 sum…

in-lambda a

3

Page 48: Ruby closures, how are they possible?

Cool!!

The lexical scope explains the examples

Page 49: Ruby closures, how are they possible?

Cool!!

The lexical scope explains the examples

But… how exactly??

Page 50: Ruby closures, how are they possible?

Ok, let’s start from scratch. How does Ruby executes programs?

Page 51: Ruby closures, how are they possible?
Page 52: Ruby closures, how are they possible?

0002 putself 0003 putobject 2 0005 putobject 2 0007 opt_plus 0009 opt_send_simple puts 0011 leave

2

rb_control_frame_tpcspselftype

YARV internal stack

[TOP LEVEL]self

2

YARV Control structures stack YARV Instructions

CFP

Page 53: Ruby closures, how are they possible?

https://github.com/ruby/ruby/blob/trunk/vm_core.h

Page 54: Ruby closures, how are they possible?

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 0000 trace 1 ( 1) 0002 putspecialobject 1 0004 putspecialobject 2 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple <callinfo!mid:core#define_method, argc:3, ARGS_SKIP> 0012 pop 0013 trace 1 ( 4) 0015 putself 0016 opt_send_simple <callinfo!mid:greet, argc:0, FCALL|VCALL|ARGS_SKIP> 0018 leave == disasm: <RubyVM::InstructionSequence:greet@<compiled>>=============== 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 putself 0005 putstring "hello" 0007 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0009 trace 16 ( 3) 0011 leave ( 2)

def greet puts “hello” end greet

Page 55: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

def greet puts “hello” end greet

Page 56: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greet

def greet puts “hello” end greet

Page 57: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetgreet

def greet puts “hello” end greet

Page 58: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetgreet

def greet puts “hello” end greet

Page 59: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greet

def greet puts “hello” end greet

Page 60: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

def greet puts “hello” end greet

Page 61: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

rb_control_frame_tpcspselftype

[METHOD]

0004 putself 0005 putstring "hello" 0007 opt_send_simple puts 0011 leave svar/cref

special

def greet puts “hello” end greet

Page 62: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

self

rb_control_frame_tpcspselftype

[METHOD]

0004 putself 0005 putstring "hello" 0007 opt_send_simple puts 0011 leave svar/cref

special

def greet puts “hello” end greet

Page 63: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

self

rb_control_frame_tpcspselftype

[METHOD]

0004 putself 0005 putstring "hello" 0007 opt_send_simple puts 0011 leave svar/cref

special

“hello”

def greet puts “hello” end greet

Page 64: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

self

rb_control_frame_tpcspselftype

[METHOD]

0004 putself 0005 putstring "hello" 0007 opt_send_simple puts 0011 leave svar/cref

special

$ “hello”def greet puts “hello” end greet

Page 65: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

def greet puts “hello” end greet

Page 66: Ruby closures, how are they possible?

Ok cool, what if the method has local variables?

Page 67: Ruby closures, how are they possible?

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 0000 trace 1 ( 1) 0002 putspecialobject 1 0004 putspecialobject 2 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple <callinfo!mid:core#define_method, argc:3, ARGS_SKIP> 0012 pop 0013 trace 1 ( 5) 0015 putself 0016 opt_send_simple <callinfo!mid:greet, argc:0, FCALL|VCALL|ARGS_SKIP> 0018 leave == disasm: <RubyVM::InstructionSequence:greet@<compiled>>=============== local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1) [ 2] str 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 putstring "hello" 0006 setlocal_OP__WC__0 2 0008 trace 1 ( 3) 0010 putself 0011 getlocal_OP__WC__0 2 0013 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0015 trace 16 ( 4) 0017 leave( 3)

def greet str = “hello” puts str end greet

Page 68: Ruby closures, how are they possible?

local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1) [ 2] str

The local table

Page 69: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

def greet str = “hello” puts str end greet

Page 70: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

strsvar/cref

ep

def greet str = “hello” puts str end greet

Page 71: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

“hello”ep

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

def greet str = “hello” puts str end greet

Page 72: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

ep

“hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

def greet str = “hello” puts str end greet

Page 73: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

epself

“hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

def greet str = “hello” puts str end greet

Page 74: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

epself

“hello”

“hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

def greet str = “hello” puts str end greet

Page 75: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

ep

“hello”

$ “hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 getlocal 2, 0 0013 opt_send_simple puts 0017 leave

def greet str = “hello” puts str end greet

Page 76: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

$ “hello”def greet str = “hello” puts str end greet

Page 77: Ruby closures, how are they possible?

Got it, but what about blocks accessing variables on lexical

scope?

Page 78: Ruby closures, how are they possible?

……… == disasm: <RubyVM::InstructionSequence:greet@<compiled>>=============== == catch table | catch type: break st: 0010 ed: 0014 sp: 0000 cont: 0014 |------------------------------------------------------------------------ local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1) [ 2] str 0000 trace 8 ( 1) 0002 trace 1 ( 2) 0004 putstring "hello" 0006 setlocal_OP__WC__0 2 0008 trace 1 ( 3) 0010 putobject 3 0012 send <callinfo!mid:times, argc:0, block:block in greet> 0014 trace 16 ( 6) 0016 leave ( 3) == disasm: <RubyVM::InstructionSequence:block in greet@<compiled>>====== == catch table | catch type: redo st: 0002 ed: 0009 sp: 0000 cont: 0002 | catch type: next st: 0002 ed: 0009 sp: 0000 cont: 0009 |------------------------------------------------------------------------ 0000 trace 256 ( 3) 0002 trace 1 ( 4) 0004 putself 0005 getlocal_OP__WC__1 2 0007 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0009 trace 512 ( 5) 0011 leave ( 4)

def greet str = “hello” 3.times do puts str end end greet

Page 79: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

def greet str = “hello” 3.times do puts str end end greet

Page 80: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

def greet str = “hello” 3.times do puts str end end greet

Page 81: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

“hello” ep

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

def greet str = “hello” 3.times do puts str end end greet

Page 82: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

ep

“hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

def greet str = “hello” 3.times do puts str end end greet

Page 83: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcspselftype

[TOP LEVEL]

:greetself

special

rb_control_frame_tpcsp

selftype

[METHOD]str

svar/cref

ep3

“hello”

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

def greet str = “hello” 3.times do puts str end end greet

Page 84: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

rb_block_tiseqep…

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

def greet str = “hello” 3.times do puts str end end greet

Page 85: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

svar/crefspecial

rb_block_tiseqep…

rb_control_frame_tpcsp

[METHOD]ep

times…

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

def greet str = “hello” 3.times do puts str end end greet

Page 86: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

svar/crefspecial

svar/cref

rb_block_tiseqep…

rb_control_frame_tpcsp

[METHOD]ep

times…

rb_con…pcsp

[BLOCK]

ep

special

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

def greet str = “hello” 3.times do puts str end end greet

Page 87: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

svar/crefspecial

svar/cref

rb_block_tiseqep…

rb_control_frame_tpcsp

[METHOD]ep

times…

rb_con…pcsp

[BLOCK]

ep

specialself

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

def greet str = “hello” 3.times do puts str end end greet

Page 88: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

svar/crefspecial

svar/cref

rb_block_tiseqep…

rb_control_frame_tpcsp

[METHOD]ep

times…

rb_con…pcsp

[BLOCK]

ep

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

specialself

“hello”

def greet str = “hello” 3.times do puts str end end greet

Page 89: Ruby closures, how are they possible?

0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 leave

rb_control_frame_tpcsp

[TOP LEVEL]

:greetself

special rb_control_frame_tpcsp

[METHOD]

0004 putstring "hello" 0006 setlocal 2, 0 0010 putobject 3 0012 send times 0016 leave

strsvar/cref

ep

3

“hello”

svar/crefspecial

svar/cref

rb_block_tiseqep…

rb_control_frame_tpcsp

[METHOD]ep

times…

rb_con…pcsp

[BLOCK]

ep

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

specialself

$ “hello”def greet str = “hello” 3.times do puts str end end greet

Page 90: Ruby closures, how are they possible?

https://github.com/ruby/ruby/blob/trunk/vm_core.h

Page 91: Ruby closures, how are they possible?

And what if that scope doesn’t exist anymore?

Page 92: Ruby closures, how are they possible?

The heap and rb_proc_t to the

rescue!

\o/

Page 93: Ruby closures, how are they possible?

Stack vs Heap

:greetselfstr

“hello”

RString

Page 94: Ruby closures, how are they possible?

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1) [ 2] f 0002 putspecialobject 1 0004 putspecialobject 2 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple <callinfo!mid:core#define_method, argc:3, ARGS_SKIP> 0012 pop 0015 putself 0016 opt_send_simple <callinfo!mid:greet, argc:0, FCALL|VCALL|ARGS_SKIP> 0018 setlocal_OP__WC__0 2 0022 getlocal_OP__WC__0 2 0024 opt_send_simple <callinfo!mid:call, argc:0, ARGS_SKIP> 0026 leave == disasm: <RubyVM::InstructionSequence:greet@<compiled>>=============== == catch table | catch type: break st: 0010 ed: 0013 sp: 0000 cont: 0013 |------------------------------------------------------------------------ local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1) [ 2] str 0004 putstring "hello" 0006 setlocal_OP__WC__0 2 0010 putself 0011 send <callinfo!mid:lambda, argc:0, block:block in greet, FCALL> 0015 leave ( 3) == disasm: <RubyVM::InstructionSequence:block in greet@<compiled>>====== == catch table | catch type: redo st: 0002 ed: 0009 sp: 0000 cont: 0002 | catch type: next st: 0002 ed: 0009 sp: 0000 cont: 0009 |------------------------------------------------------------------------ 0004 putself 0005 getlocal_OP__WC__1 2 0007 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0011 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

Page 95: Ruby closures, how are they possible?

def greet str = “hello” lambda do puts str end end f = greet f.call

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

Page 96: Ruby closures, how are they possible?

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

rb_control_frame_tpcsp

[TOP LEVEL]ep

rb_control_frame_tpcsp

[METHOD]ep

fsvar/crefspecial:greet self str

svar/crefspecial

Page 97: Ruby closures, how are they possible?

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

rb_control_frame_tpcsp

[TOP LEVEL]ep

rb_control_frame_tpcsp

[METHOD]ep

fsvar/crefspecial:greet self str

svar/crefspecial“hello”

Page 98: Ruby closures, how are they possible?

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

rb_control_frame_tpcsp

[TOP LEVEL]ep

rb_control_frame_tpcsp

[METHOD]ep

fsvar/crefspecial:greet self str

svar/crefspecial

Page 99: Ruby closures, how are they possible?

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

rb_control_frame_tpcsp

[TOP LEVEL]ep

rb_control_frame_tpcsp

[METHOD]ep

fsvar/crefspecial:greet self str

svar/crefspecial

self

Page 100: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self str

rb_control_frame_tpcsp

[METHOD]epsvar/cref

specialself

lambda

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello” strsvar/crefspecial

self

“hello”

Page 101: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self str

rb_control_frame_tpcsp

[METHOD]epsvar/cref

specialself

lambda

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

strsvar/crefspecial

self

“hello”

Page 102: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self str

rb_control_frame_tpcsp

[METHOD]epsvar/cref

specialself

lambda

rb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

strsvar/crefspecial

self

“hello”

Page 103: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self str

rb_control_frame_tpcsp

[METHOD]epsvar/cref

specialself

lambda

rb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

strsvar/crefspecial

self

“hello”

Page 104: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self str

rb_control_frame_tpcsp

[METHOD]epsvar/cref

specialself

lambda

rb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

0004 putstring "hello" 0006 setlocal 2, 0 0010 putself 0011 send lambda 0015 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

strsvar/crefspecial

self

“hello”

Page 105: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

lambda

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 106: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 107: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

lambda

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 108: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

lambda

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

svar/cref

rb_control_frame_tpcsp

[BLOCK]ep

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

special

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 109: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

lambda

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

svar/cref

rb_control_frame_tpcsp

[BLOCK]ep

specialself

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 110: Ruby closures, how are they possible?

rb_control_frame_tpcsp

[TOP LEVEL]epf

svar/crefspecial:greet self

lambda

strsvar/crefspecial

selfrb_proc_trb_block_t

EP

svar/cref

rb_control_frame_tpcsp

[BLOCK]ep

specialself

“hello”

0004 putself 0005 getlocal 2, 1 0007 opt_send_simple puts 0011 leave

[ 2] f 0006 putobject :greet 0008 putiseq greet 0010 opt_send_simple core#define_method 0012 pop 0015 putself 0016 opt_send_simple greet 0018 setlocal 2, 0 0022 getlocal 2, 0 0024 opt_send_simple call 0026 leave

def greet str = “hello” lambda do puts str end end f = greet f.call

“hello”

Page 111: Ruby closures, how are they possible?

$ “hello”

Page 112: Ruby closures, how are they possible?

https://github.com/ruby/ruby/blob/trunk/vm_core.h

Page 113: Ruby closures, how are they possible?

Acknowledgements

Pat Shaughnessy

Page 114: Ruby closures, how are they possible?

Questions?

Page 115: Ruby closures, how are they possible?

Thanks!

Carlos Alonso Software Engineer

@calonso