Tuesday, October 04, 2016

Ruby Conf 12 - Dissecting a Ruby Block by Pat Saughnessy

well
hi will two-lap
I realize I'm the last person between you guys in the bar
I'm really impressed that you're still here time there's been some amazing
talks today I've seen a lot of them
so amazing talks going on right now so thanks a lot for coming I really
appreciate it
I and thanks to Ruby sensual and often you guys are in the room
I'm for giving me a chance to talk to rubicam like a once in a lifetime
opportunity I'm really excited
on it it's thrilling for me to be here thanks a lot
on my name is Pat China Sea and I'm to be talking about blocks
so that's why I talked for 45 minutes about Ruby blocks
and back together we're gonna be dissecting
a ruby block so don't worry there be no blood no gore
I know lab animals will be harmed in this experiment
I what what I'm gonna do is look at how Ruby implements blocks internally
and see what we can learn about blocks by doing that and I'll be talking about
I'm mats is Ruby implementation today not about JB rebellious
other versions a movie I'm before going into blocks a
let me just start by saying a little bit about myself probably have heard before
I work at a company called mckinsey which is a management consulting firm
but I'm not a consultant I just I'm just a Ruby developer every code
for them I'm in my spare time I read a blog
about Ruby development at Pats on a C-dot net I am really excited actually
just finished my first book I wrote a book
I've been working for the last say thank you
I just release a book this week on Monday called
Ruby under a microscope and it's all about I Ruby internal
suck taken six months of my my job and I went to
into my just at my house I wrote about how Ruby works
and the way I the way I like think it is I went on a long road trip
was kinda like visiting Japan or foreign country where you don't really know the
language
and you see all these amazing exotic sights and your
on you know but you begin to learn a little bit the local language get to
know people there you can appreciate their customs and their food in
that's what it was like for me so the book is for today travel journal about
I Ruby MRI internals also touch on Jay will be in the billions in the book
I'm so if you're into internal stop and i actually the presentation today this
is really a synopsis above the chapters from the book
I please check it out on so
the first question probably have for me is look at pat why Ruby internals
who cares about how Ruby works all i care about. is
that Ruby does what it's supposed to do you fight takes a value Pfizer something
into a hash I see evidence or a
I need to know is that I'm gonna get it back when I give it the same key
II I don't care how really works I'm busy I had a job to get stuff done
I have to you may have an open source project tonight I work on my spare time
on the weekends
it was time to look into Ruby internals and figure it out
you know I took sixth month of I did and I'm kinda crazy maybe
but I'm here the reasons why I did it may be wise to learn about Ruby
internals to
so I can pick up three reasons on the first one is I think it if you study
group internals
you can help you become a better Ruby developer I think you can learn
about the language more deeply than you may have up
you can look at more deeply than you did before I'm you can learn about how ruby
was intended to be used
how mats and the rest at the core team intended the language to be used not
just use it the way you happen to learn how to use it
I'm and I'm I think you can learn a lot just become a better developer for it
I'm
maybe a second reason could be there's a lot to learn from the core team
you know that which in the other teak people on Team are there really smart
people that SOB difficult problems
and maybe you can learn from their solutions their algorithm their code
and learn about me you know maybe pull some ideas from them that you can try in
your own projects
I'm so there's a lot of amazing solutions you know we can all learn from
on its a little inaccessible miss you take the time to learn it I mean I think
the last reason the most important one is just a lot of fun I had a black I had
so much fun learning about Ruby trials
and I hope you guys I'm guilty so that today if you if you like it
then check out the book has a lot of really amazing stuff going on there
fascinating to me to learn how language works internally
I never knew this I'm not a computer science major anything and so for me to
learn about how language worked
internally it was just it was just super fun so that the most important
have fun on so today I'm not talk about blocks
you know here's a black and it seems kinda hard to believe that there's
really that much interesting to say about blocks
you know what can we say that well we call them you call a block
you can pass an argument to block like this on
and you know most about special here rubicam you go are you guys can tell me
how this
you what this code will do in two seconds or less you can tell me what the
score is gonna do
you know what am I possibly gonna say what can we say about blocks that that
interesting
on the hold that thought will get to the blocks in a second the real reason
however I want to talk about blocks
is I'm when I think back to when I first came across Ruby
I imagine a lot of you here had the same experience you for star ruby for me was
in 2000 eight maybe and before that I was a PHP
I job at C plus plus developer I did a few other random things to
on yes if I wanted to write code that did this in C
I have to say you know in its I a semicolon
for Francies I equals 0 semicolon I less than 10
semicolon I plus plus Francies brace
lullaby with much more verbose way of doing the same thing
my first came across this is my might have been two thousand 8
I thought to myself wow this is something different I haven't seen
anything like this before
I'm you know it was it seemed really elegant and beautiful to me
and it got me to think twice about Ruby I thought to myself
ruby is something special and I think back about that
it it really was the blocks the way that you can use blocks and Ruby
that got me to fall in love with the language so you know aside from all the
technical stuff about to go into
for me the real reason I wanted to talk to you guys today about blocks was
it's what I like the most about Ruby our hands you know
think back to your own history where you discover the language what it was about
Ruby that made you fall in love
with enough to come to rubicam so for me it was blocks
so what am I gonna save up blocks while the first thing I want to do is define
what is a block enough we ask that question what is a black what can answer
to get
you know and so the way I want to do that is it mattered if I could slice
open a block and look inside
you know what's inside a block other moving parts in there my gonna see blood
gots chromosomes you amoebas
by the slice a peaceful block at look at under look added under a microscope
you what I see on in so the first half the presentation to talk about
on what blocks Armin answer that question
what is a block and we'll find out in a few minutes
on that blocks are ruby's implementation of closures
and define what a closure is on the way on at the second half miss which here to
talk about closures and met a programming
and how those two things are related so two different very different concepts
but I think they're actually related to each other
and so on we'll talk about that second
so let's get into it if you were to look inside the Ruby C source code
and you were to try to figure something out about what blocks are
the first thing that you would see is that there's a/c memory structure called
RB underscore block and I'm not showing the conference over here
the reason why is I want us to discover as we go along what's in this structure
on and but the nice thing about studying Ruby internals is
if you had a question like this you know what is a block or what is object what
is a module
you know you can actually directly answer that all you need to do is go
into the C code
find the definition up this or that or the other thing and that's your answer
you have to think about it very much you can just look at how it was implemented
and so that's not maybe another reason for studying Ruby internals as you can
answer all these sorts of questions that you might have about how language works
or how it was intended to be used
so before we go any farther away about my diagram saw you know today and also
my ebook
I have a lot of pictures it's like an illustrated book on
my pictures are not definitive exhaustive definitions up
exactly how it really works I'm not gonna show you every single thing
inside the block structure on and is the reason why is I want to point out to use
the details about Ruby internals I think are important for
for you Ruby developers to know on there's a lot of other very technical
things in London nitty-gritty details that may be on
on is interesting and so I'm gonna glass over ignore some of those details
and so my diagrams are oversimplified vers reality
that'll make them hopefully easier for you to understand as well
I made it easier for me to drive them to so
what we're going to do is I were you do a series of experiments
and the reason I called the book will be under a microscope is I wanted to use
for the scientific method
for discovering and learning things about Ruby you know it's one thing to
start talking about how it works and what does
it's nothing to test your hypothesis with an experiment
I'm so I'm not going to real experiments today I was going to do it you know if
you simplify experiments we have much time
but in the book I go into more detail about on one thing or another and
actually
run some code experiments are written in Ruby codes you can download them in one
them yourself if you're interested
so the first thing I do is really the most basic thing you can do with the
block is call a block so how do we call a block
so not rocket science. all you know how to call a block here's an example
on here's a block that takes us string value the quick brown fox
the rest of that of course is jumps over the lazy dog that didn't on slide
but we're gonna come back to that string over and over again and you're gonna get
very bored and tired of hearing me say that
on and we're gonna save it in a string variable call
II local very local STR and then we're gonna print that out and we'll do that
ten times
not very instinctive good but what it does is it allows me to answer the
question
what is a block and so the first the most obvious answer to that question is
well
it's right there on the screen everything between the do keyword and'.
and keyword
you know the first most obvious definition of a block is it's just a
code snippet
it's something that I'm units code that you type in it's sort of like a function
if we were to look inside Ruby you know through a microscope so to speak
this is what you would see so that RB block
see structure I'm sorry now on the right announced showing you one up
feels are one of the values inside that in there are many more but here's one up
on this call I S
EQ and I think and help me out here core team I think that stands for
instruction sequence and that's a point or two points to
and instruction sequence that some showing on the left side
I'm yeah and instruction sequences a series of bytecode a virtual machine
instructions
the first one is put streams that dynamic et cetera et cetera
don't worry don't try to read that don't try to understand it I'm not gonna
explaining that today
I have a lot more that in my book ob
but what I wanted to point out is this is really want to block it
its a snippet of code internally this is what it looks like
on just taking a step back for a moment I will stay just one
you know me one minute about how on the virtual machine works and how these by
code instructions work
at a ten thousand foot level when you look at ruby from you know from a
distance
the wave Ruby works at least starting with 319 is
you give it some your code really parses that and compiled your roomie code into
these instructions
and then executes them with the virtual machine and that's what I quit she was
talking about earlier today
so on 30 wait this is our first answer to the question what is a block
its a on it's a snippet of code or a function
on now is to another spent the summer when I i'm look at how you can reference
variables from the parents cope
that sounds kinda complicated but it's really actually obvious ok you to look
at a block like this
so now I'm doing the same thing and bring the same three and ten times
I'm just doing in a more complicated silly fashion
I and so what I've done years I've taken the first happened strain
the quick brown fox and say that in the same STR variable
but I'm I'm doing and outer go oMG I call the block 10 times in the block I
think FTR to
so I have a second variable I and that when I'm saving the second half for the
string
jumps over the lazy dog and I have to put a statement that says put ass
you know string and string to so pretty simple code you can own standards
on and in fact you know what's the which thing about this is all kinda obvious
are you guys write did disorder called probably every day this is probably a
reflex
prices take this to mean that even realizing it on
you know why my points out to you well for me to something
actually kinda profound interesting going on here has to do with the
question again what is a block
so it the way I look at it is blocks happened is dual personality
a kind of schizophrenic you know they have on the one hand there a separate
function
I'm calling on the other hand their part up the surrounding
function and so that put a statement can access equally well I can access
STR you can access STR to
it doesn't it doesn't matter that's kinda obvious we all take that for
granted
but it's not you know don't take it for granted a lot goes on inside a privy to
make that work
so let's take a look inside a booby see how to implemented
on thought what am i jus a misstep through this slowly and I go through
this in great detail explain how this is implemented
so the first thing we do is we take that string the box during
we save it in a variable STR what is really do when you save
a value in a variable so we would look inside Ruby
I'm again you can tell these are super oversimplified diagrams
what I'm trying to get across here are the essential ideas
so mom first ball on the left we have a stack this is something called
not be virtual machines internal stack so the way the virtual machine works
on if you heard that the presentation earlier you know this it's a stack-based
machine as it runs those instructions that we saw
earlier I'm that local get local whatever is it runs as internal
instructions those instructions to pick lee used
are they take values of this internal stack they do some kind of operation
and they pushed the result back on the stack on so this internal stack is
actually not something that you ever see as a Ruby developer really need to know
much about
on but yeah I just remember that the the virtual machine inside Ruby
is a stack-based machine and so when we save a value in a local variable like
STR example that value get saved
on that stack internally okay on the right is actually a different stack
so on the right to something called our beacon full frame structure and I'm
showing one member from that structure
and which he asked earlier you know how many members are in this I think there
are 11
so there's a lot more going on you're not showing you but I what I want to
point out is that there's one pointer
the DFP which I think stands for dynamic frame pointer
that indicates that you will be used to keep track of where the variables are
for the current on for the current scope leading to explain here is that
as your Ruby program runs you call from one method to another to a block to
lambda
you have this Ruby call stack you build up and if you ever run the command put a
scholar
that will print out that whole call stack and so each level on that call
stack is represented by this
RB control frame structure on and so what you have to imagine here then it
will have time to explain all this today
that there's a stack or an array of these control frames
that represent your Ruby call stack so if you think about it inside ever be
there to stacks there's a
Ruby stack on the right and is the internal virtual machine stack
on the left those two things are related and connected
anyway let's get back to block so how does this work so
now we've said the value in st. are and now we're going to call the block
so what happens well actually we're not calling the block army what are we doing
here
what we're doing here is we're taking a number 10
and we're concerned that mean object that the receiver other message
the 10 is an instance up the fixed number integer class
and we're sending a message to it which is the times method
so what we're doing is we're calling the times method on that class objects known
and that has nothing to do with the block back or not on the block at all
what we're doing is we're
we're taking that block more pass it into the method as an argument
so it's on there's more going on in my think so let's look at
what happens inside a ruby at the moment when you pass a block into a method
called an argument
okay we're not going up come on the block at were simply referring to that
block for the first time
so when you do that when you when you first refer to our use a block
Ruby says oh I have a new block I need to create a new RB block structure
and so what it does and again I'm I'm showing and ok over simplified version
up the same structure but it creates a second value in their
any copies that the DFP a copy that from the control frame
to the block okay to remember that the FBI was a pointer over to
the internal stack where the local variables for that method were stored
so what's going on years interesting is that ruby is saving information inside
the block
about where you first referred to that block from
where you I've decided to pass it into a method
so blocks are not as simple as they seem not just the code snippet to have this
other value inside of them
which is a a pointer to the environment where you
reference them from interesting on what we want that type from NC where would
where we go
okay so now we're calling not attend dot times methods were calling into the
times method inside the pics numb class
and so we have you call a method in Ruby it creates another stack frame on that
internal static which is a bunch of values
on the air in the lot details are not showing I just want to get across the
fact that
as you call deeper and deeper into your code it creates more more the stack
frames
on now 269 primes class is implemented in C++
not something you write your cell on but it works the same way that you probably
would write it
loops over you know the number 0- 12 up to n -1
so in this case will go up to nine and finally now it's time to call it a lot
so that will
echoed inside the pics numb class will yield to the block
yield is just a fancy word to use for calling on the blocks from Shin
on and in Los a passenger argument if you want to
if you want to okay so now I'm in the block I'm gonna create the STR to
variable
where I save jumps over the lazy dog and I and then open up the two strings we'll
see how that works
okay so now I'm getting a little complicated in my
internal stack my yard internal stack now I have 3 stack frames impact is more
than £3m
glassing that over to the fort stack frame in there but
just to keep things simple today on the bottom we have
the parents cope where the STI variable was
in the middle we have another scope for the times method
and then on the top we have the top of the stack is now being used
as we run the code inside the block and so that's where the STR to variable goes
and so they put us call when it says put s STR STR to
the code input at is able to access both STR to
in the car in scope and then using that the FB point2 go down to the parents go
farther down on the stack and finance STR variable
and the reason you can't do that is that when yield to a block in Ruby when you
call a block
Ruby take that DFT pointer out of the block and put it onto
back so that you all the code inside your block is able to access
the environment where you originally again when you first referred to tap
Locke
so ruby is not wasted emerging those two things together the
original surrounding environment and the current scope up the block itself
so that side now back to that dual personality that's the way blocks were
able to behave in this way
how they're smart enough to do both things
on just taking a step back and reviewing we found out so far discovered two
to feels our values inside the block structure we have
the iseq pointer this is the instruction sequence
that points over to the again a series a bytecode instructions that the virtual
machine is going to run
so this is the compiled version might function and it has that dynamic frame
points or DFP
that points down to the stack and again not to wear the stack is
you know at the moment we run the code but it to the referencing environment
where I first referred to that stack
that that block that turns out in computer science is a fancy
name for this combination of two ideas a function
and the environment where you refer to that function from I and that was
invented a long time ago back in 1975 Annabeth
opyat applied the back in 1975 I
an MIT professor named Gerald susman and his colleague I steal wrote a paper
called
scheme in extended I interpreter for extended lambda calculus
sounds like complicated in spree it's a pretty hard-core academic paper
exactly online you can download it read it yourself ID Act did the other day was
really fun
on I love the stuff I'm kinda language geek
on and this paper defines in and
and explain their implementation of a language called scheme
scheme is a dialect less and what's interesting about scheme scheme is still
being used today
I is that it was the first time that in computer science there was a formal
definition of the word closure
so they define if I did on this academic paper what a closure is and here's how
to find it
so we just read through this for second year to solve this problem night don't
know upon their solving
on we introduce the notion of a closure up which is a data structure containing
a lambda expression
whatever that is and environment to be used when that lambda expression is
applied to its arguments
so can a hot you know fun you know convoluted language here a lambda
expression at a fancy way of saying a function or method
and job applying that land expressions with
arguments just means the call the function in passing yards
but if you think about this for a minute this is actually what we have in Ruby
with the block we have a function and environment to be used
when we call a function you backing up this is what a block is
it's the function on the top left and the environment on the lower left
and so I and so what we've done here is we've shown that blocks in Ruby
are are ruby's implementation of closures ruby is taken
and i've not do this on purpose or you know indirectly but ruby is taken
I'm a concept from the nineteen seventies and applied to
language that was invented in nineteen nineties and i were so using today
I find a common staying on what we want to talk about Lambert slams a related
two blocks and let's see if we could do experiment figure out
you know what land as our on before we get to the lambda
themselves you know where the woodland come from you know why in the world is
Ruby have a key word that is the Greek letter
lamb is a a letter in the Greek alphabet what does have to do with computer
science
I'm so it turns out the same thing that Ruby borrowed the idea
lambda are the word Banda from less this is the first computer that ever ran
on the list languages from the early nineteen sixties
with was invented by John McCarthy in the late nineteen fifties actually so
this is
what is that almost job fifty years ago now
and a in the list John McCarthy introduce the idea the lambda
which is the way in so here's a list how you would create an anonymous function
I'm not a list developer and many do your might be I'm what I think this is
doing is
its defining a function waterfront see the list
but when I think it's doing is too funny a function that takes argument
and then divide that argument by two and returns that value
so it sa but it's not doing that immediately its returning a function as
a value
and so what list introduced in other functional programming languages do this
to
they allow you to treat coder functions as data values
I and so they you know quote-unquote they treat code as a first-class citizen
sewing room you can do the same thing Ruby Baroda land the key word from this
and I'm curious you know here's my thing silly example
on now I'm doing in in an even more complicated and confusing manner
so what I want to do is demonstrate how you use them to in Ruby
we're gonna do the same thing when a print out the same string I'm not ten
times as one time today
well for this experiment so how does this work
so I'll let you guys might know exactly how lambs work on but OK from you
donor have and use one in a while we go through it the way this works
is on the bottom I call a method display message
cause into the method in the method we save the quick brown fox the first half
at the string in a variable
STR same thing we did earlier and then we have a block that takes
on the first after the string and print that out concatenated with the second
half a string
except the difference here as I don't call the block immediately instead I say
lambda
and what lambda does the returns that block has a value it converts it into a
tape a data value of some kind
and that becomes since that's the last thing in the display message
method that becomes the return value for that matter
and then finally we say dot call at the very bottom so it's not until the bottom
here right they don't call that it prints out
people straight you can try this on your own computers
so I'm let's go through this and see how it is implemented inside Ruby
know what goes on when you can when you use land so will go through one minute
I'm slowly at first thing is
I take the clock string I put it in the STR burials same story here
on you know not no surprise we save the string
on the stack and there's a control freak structure on
and the bottom empty one is the outside scope and then we have one
for the message but that in that method ever calling
should be display message on okay what do we do next
now we call them to so what happens inside Ruby when you call the land the
keyword
that's going to be a complicated diagram don't panic I'm gonna go through this
slowly let's see if we can figure this out together
on and meet a couple minutes just explain this picture
so before I get all the boxes and arrows on the right let me talk about the two
words on the left stack and heap
so what i'm indicating there is this really two different types the memory in
your Ruby process
are really in any process that matter their stack memory
that's what we've been talking about so far were you push values onto a stacking
pop them off
stack is used for values are very temporary in nature
so they're only ballot or they only needed for a short period time usually
during the context that one method
or function on the on the bottom under the dotted line we have to keep
and a lot you may know the keepers for whereas for when you wanna savings for a
long period time
know when you on one some value to persist around there are you know the
liar around for a while so you can use it later
I N the biggest or most obvious example abusing the heap in a review program is
when you create an object
it gets saved in heat will be out it's a memory at heap and use it for that
object
so what's going on here when I call them that what is it do you well the first
thing it does let's start from the top left take that internal stack
where we have that FDR variable any copy that
from the stack copy that stack frame down into the heat
so creates a persistent sorta on
a new second copy all the same information what's special about that is
it
now in the heat so I can persist for a longer period of time
on and the other thing too because it creates on the bottom and i know i don't
know everyone can see this summer you're pretty far back
is a structure called RB underscore yen VY
in this is a I with call the environment object I i assume
and this is a sorta the structure that will be used to manage that keep copy of
the stack
on so interesting what else is going on here the other thing that really does on
the right is it takes the control frame structure
and a cop is it into something called RB underscore Prock
structure and as you might know some you the return value avail and a
key up the land the key word is actually a prop object
and so this is Rubys internal representation of approx
and you can see it put in there the DFP pointer the iseq pointer
and a couple other things on and one instinct detailed notice here that
inside the prop structure is a block structure
and so in fact what we what we're seeing here by looking at the way the
these things are implemented that proximal and as and blocks are all
really the same thing
they're all closures they're all the combination of the iseq pointer
the colder the function and the DFP pointer which is the
referencing environment through all really different ways looking at the
same thing
and so when you call them that creates that new object copies a stack frame for
that environment into the heat
and then it Tom and then it returns at proctor you as a as a return value
okay so finally ready to print out the string and rate is a display message dot
calling its gonna perhaps during a work just fine
but what I want to point out here's something interesting which is on
if you look at this carefully think about it how is it possible that my call
dot call at the bottom it prints out the whole string
if you look at that first variable STR that the local variable inside a method
normally when a method returns
all the variables that you create in a method are you know they're free to
release they're gone forever
but obviously here that STR variable lives on
that serve a second lease on life able to do more you know more good for you
good morning your program how does that work well that's really
back up to this picture that's the whole reason why
ruby is doing all this work all this copying all these new structured players
all this is just so that you can continue to refer to the environment
where you call Amanda from so at the moment I call and that that environment
not only what's inside the land a
but the surrounding values are all saved away that later when I
they got call it works fine and
looking at how that's implement inside Ruby on its or other similar pictures
except the opposite so what we do now is Ruby take the DFP pointer from the block
that inside that prop and copies it up into a new stack frame
that it sets up to run the code inside the block and remember in the block
we're creating STR to left the dog park the string
so that is pushed onto the stack now on the top left
and its save that the FP pointer there which points now it points out to the
heap
where the referencing environment that in you know copia reference
that environment say so it's just like on a normal block
except that detail the DFP now pointing out to the heat
so that's all and its work on so it's mine it's not about blocks
and I we've seen how blocks and lamb is approx are all the same thing in there
all
on and they're all closures I'm not just here to talk about closures and mentor
programming the two different period
very different ideas how are they related and you know what is
met for me have to do closures the first of all I'm so as to experiment using a
closer to the
find a method so what the world does that mean on
let's take another example let's say I creat now I'm gonna wrap my exciting
I'm box dog wrap it up in a class democratic last fall quote
and I'm you on how to create methods what you do is use a class
name a class quote and use a deft this staff that def the other thing you start
typing method definitions
and use the Deaf keyword yet all very obvious
so how do you do met a programming what is better programming
well one way of doing that a programming and ruby is to dynamically create
methods
and all that means is instead of saying def teef I can say
define method display message so the only difference between this what you
normally do
and this the defined netted met method
is that you pass the name of the Met up the new method as a parameter to it
so the name is my new Massa on my new method is display message
shit I have a different sample that was on tongue twister
so Here I am too funny a method and more confusing calm blue demanded that
doesn't make as much sense that's what made a firming really is all about isn't
self on but you know in a real example what you do is you probably have a loop
here you might create 10 or 20 methods of the same time you're going through
that you know each name
each method names may be an array or maybe the name on the map it is from
user input or from a database query to the IP certainly
valid reasons for doing something like this but what I want to point out here
something different
I think there's actually some there's another minor detail are you may not
have noticed that
different between yes and
which is that when you say defined method you pass on that the name
then you have to say do at so that that
the methods body is actually a block you're passing a block
into this the Find method method
and that's not what we did over here we do said def the name and wheat are
typing in the code
and remember blocks are closures so because the block is the closer it means
that the code inside of the block
can access things in its surrounding environment
now in this example there really is nothing interesting around that is no
there's no reason to do this well maginnis in Europe your Ruby application
there was an interesting environment there was a place in your code where
you had a lot of instinct values you wanted your new method to be aware of
that access to so I'll make up a contrived example let's say
I only remember to put the the Fox the first half a string
in in the instance variable at STR
but then I discovered later I have the dog the the second happens during
STR to somewhere else in my code you know how can I
how can I allow my exciting method to bring out the same thing both
strings together well sense that the closure is able to access
the on instance variable it's going to become a method up this
quo class it's able to access equally well at STR
on the top an STR to which is on
in the surrounding scope there one confusing detail here
here as I have to say quote dots and define method
that's because the defined method on method is a is private to the module
class:
but other than that it's actually not that complicated so this is how you can
define a method
using a closure okay let's take another example
on let's look at sort of the classic example have met a programming
amid a programming really means to write code that writes code
and in Ruby on the simplest way to do that is to say
eyes to use the email function if I create a string like
put ass two plus two %ah again this is silly but you can imagine
I really example we are dynamically writing code that based on some kind of
data
you're getting from somewhere on you can pass that stricken to eat out what it
will do is it will
recursively call that virtual machine again and on compile that code into
those bytecode instructions and then run
I and so in this case is a printout for not really interesting
one one detail about you know that maybe didn't know is that its also a closer
so the code inside this string can access the environment around the call
to me Val
so what does that mean and how does that work well another way of doing this is
to use the binding
keyword this allows you to formally specified that environment
that you want the Val to work with on so
so madge in for minute I went back to my core class and I said
def get bindings like create a method called get binding
and the reason I want to do that you'll see in a minute reason I wanna do that
is to be able to access
the scope or the environment inside of this class
on so well so I can access that at st. are variable
so hold that thought let's move on and look at I'm
creating a new instance of the quote class of the object equals quote got you
not have a new object on what I want to do is something so let me take a moment
to explain
just for for 10 seconds or less how Ruby implements objects and I have a lot more
about this my book
on there's a on a lot more detail chapter on objects
but in a nutshell we have you created object Ruby creates
a structure called are object at least for custom object that you write
now for strings and arrays something else on book one of the other details I
didn't show now control frame structure is that
there's another thing called a self pointer that points to
the current value itself object in which you're running
at the moment solve your problem me with self but if not
just imagine as you go through your Ruby call stack you call one method called
another call another
each one of those methods belongs to some object some instanceof some class
and so the way will be implements that is in this control frame structure is
one of these for each level in your Ruby call stack
there's a self pointer that points to I'm which
instance which object instance is currently the cell
current value cell on our object
on structure itself has some other things in it but the most important to
values are
there's a class with a que that's the class pointer that will point out to
indicate which class this object is instanceof
and then there's another thing called I DPTR the instance variable pointer and
its points to an array of
the instance variables for this object I'm so in this case for my hat at st.
are in that and that iraq
okay to back for example now we know something about how objects work
internally
and have created an object or BJ Eagles quote that new
and I called me Val and what I want to have happen in this
a course that will work you can try this if you really want to what I want to do
here is
allow the compiler when it compiles that strain
to compile in the context I love the old BJ object
and so the way you can do that in with the email method is you can pass and
a second parameter which is that binding and remember we got that
sourcing 0 BJ dot get binding the backing up to my
class at the bottom we have that that method that we saw earlier get binding
that is called the special on mysterious keyword
binding and what is that doing what happens at the moment I call binding
and what is a binding anyway I'm so well we can see what it's intended to do its
gonna tell you now
when you compile that code do it in the context
up this binding not binding can be anywhere your application
and so how does that work what happens inside Ruby when I say
binding well let's take a look
on so this is the serve a similar picture what we had earlier we have on
the top we have
stack on the bottom have to keep on the top we have the control frame structure
and now my point out there's the South Point to their along with the DFP
on and all the same things will happen with the stack your copy to stack
out into the heap and it'll set the DFP pointer to the heat poppy
I'm not showing that in this pictures to keep things simple
but when you call binding Ruby will also call I'll also create a new
structure called RB underscore binding
on the lower right and in that structural save the file name the line
number where you call the binding
keyword case I wanna you know debug something you can
if you print out the binding I'll tell you on but it also creates this thing
called me and B which points to
the same environment structure we saw earlier on with the land the keyword
except this time on what I actually showing in five environment a block
structure
it turns out there's another block structure in the environment and
I'm also showing an additional value here inside the block call itself
that when you call binding a copy is not only the DFP
from that control frame into the new block a copy is also that sell pointer
and at some point to a point over to the are object
to cart value cell and that's how when I
you know compile that code using the valley it's able to access
all the way down lower left the at st. are valuable
so what we've seen here is bindings landers proxim blocks are all really the
same thing
they're all closures in all different ways of looking at the same thing
on and i find you know I think this is of passing
okay so and then just reviewing you know going back to our my original question
what is a block
now we've seen there's on three things in this block structure
RB block structure we have first I i think you'd instruction sequence
appoints the function we have to DFP did that dynamic frame pointer that points
to the
referencing environment and now we have this third thing which is the fell
pointer that points
are object I'm structure which is the current value
cell so this is really the best definition I love
you know what is a block and it's also the way out the best
at the way that ruby has implemented closures
so on Ruby the cloacal I closure ruby is a function combined with its
referencing environment and I guess what you call the object environment
so the condo objects contact are the context
about in which work on that block
so that's it for today at you guys go with you today
if you like this stuff endurance to Ruby internals wanna learn more
you buy my book Ruby under microscope on and then you find it online on my
website
thanks a lot
well
0

No comments:

Post a Comment