 Okay, so today, I'm going to be talking about blocks in Ruby and before I go there Let me just tell you a little bit about myself So as mentioned I come from Cape Town in South Africa And I'd like to take this opportunity to thank the organizers for having me here all the way from halfway across the world So this is what Cape Town and Table Mountain looks like according to the internet Well as seen from a helicopter that is so here's a more realistic view This is a picture I took from a beach That's about 25 minutes outside the center of Cape Town over there and the picture is quite fuzzy But as you can see it's still quite beautiful An interesting fact about Cape Town at the moment is that we quite literally almost ran out of water earlier this year So this is what our biggest dam looks like at the moment And as you can see there's hardly any water in it and essentially what happened is because of climate change or Some other reason that you might want to blame We've had a lot less We've had a lot less rainfall over the last couple of years than what is normal and the dams all started running low and low Until most of them looked like this Now fortunately all the Cape Townians woke up at the very last minute and started saving water at quite an astonishing rate And so we managed to avert the crisis that would have been running out of water for now and unfortunate Unfortunate consequence of this however was that all the tourists ran away But what I'm saying is that there really seems to be no risk of us running out of water anymore this year and So you all can come back now Okay, so an interesting fact about me is I also have a cat her name is Emma and she's quite adorable as you can see Unfortunately unlike Max's cat. There's no way in hell. She's ever gonna play catch with me But she does know one neat trick and that is to sit on my keyboard whenever I'm trying to do any work as Is demonstrated here Here and also here Okay, so that's enough small talk for now. So as I said today, I'll be speaking about blocks in Ruby Now you as you probably know you can do some pretty interesting things with blocks For example, you can do what I've got here, which is defining a variable outside the scope of the block And then you can use it inside a block that you pass to a method without any issues Now I recently ran into a situation in my code where this scenario seemed to stop working and my code looks something like this It was an aspect example and In this example, I had a let block that to find something called test index and Then inside my it block. I was creating two nested blocks And so the first block was being created and passed to class evil and The second block was being created inside that and passed to a method called model And it was inside the second nested block that I was trying to use test index Now based on the example, I just showed you I thought this would just work However, when I ran it, I got our spec or Ruby complaining about an undefined local variable or method test index And what was even weirder was I found that after playing around with the code a little bit that this slight modification that I made to the code Where I defined a local variable my index inside the it block and then assign test index to that and Then use my index inside these two nested blocks instead of test index the aspect example would pass without a hitch Now in order to try and figure out what was going on here I came up with the following differential diagnosis and the first theory was maybe the problem is that You can't actually use a variable to find outside the scope of nested blocks over here Inside the innermost nested block So I thought maybe the problem was because they were basically just too many blocks and I was defining test index way outside all of them You just can't do that But I quickly came up with an example showing that this seems to work just fine in general so You see I'm defining my string variable again and using it inside two nested calls two times without an issue And I'm sure you're not surprised to see that So theory number two was maybe the problem is that I'm using let to define test index So I did a little bit of digging and I found the following bit of our spec documentation That says that actually Let defines a memorized helper method and not a variable as I first thought And so I thought maybe the problem is that you can't actually use a method to find outside the scope of a block inside a block and Again, I quickly come up with an example However, that shows that this seems to work in general as well so here I'm basically just defining string as a method and Again using it inside my block that I'm passing two times and we all know this works and And so my final theory was that maybe just like some other things in this world The problem was that maybe our spec is just a bit crap. And so maybe there's And so maybe there is a problem in our spec or there's some bug in the aspect code That's making my example fail when it should have been passing But again, it didn't take me long to come up with a simple example showing that this seems to work out in general as well And so I didn't even bother to pursue this avenue of thought any further Now at this point I realized if I was going to understand what was going on in my aspect example I needed to understand the underlying mechanisms of what makes blocks so powerful and really better And so the first question we can ask of course is what is a block really? Well, it turns out that a block is rubies implementation of Sussman and Steel's closure And that is essentially defined as just a combination of the two following things It consists of a lambda expression Which is just a function that takes a set of a set of arguments and Then it also consists of an environment to be used when calling that function Now obviously for blocks this environment is going to have to include the surrounding scope in order for my previous examples to work Okay in the underlying C code for Ruby the block is actually an object and it's called RB underscore block in Ruby 2.2 and lower is actually called RB underscore block and it's got a underscore t at the end as well and It has several properties among those is the ASIC pointer and This is just a pointer to the lambda expression of the closure Then it has an environment pointer property as well and this is a pointer to the surrounding stack frame of the block In other words, it's going to point to where all the local variables of the currently executing method inside Which you creating the block is located and it's this environment pointer That is the reason that you can use variables to find outside the scope of your block inside your block And I'll show you how that works in a minute Now in Ruby any code you execute is always going to be executing inside some other method And so it will always have a surrounding stack frame So even if you think about it if you're executing code in your console that code is executing inside the evil method And we'll also have a surrounding stack frame And so in a lot of the examples I'll show you in the following slides I'll often show you the methods surrounding the code that I'm busy looking at so that I can show you that surrounding stack frame Now back to this environment pointer it turns out Ruby uses this to do some very interesting things on the stack and To show you what I mean, let's first take a look at what happens during a normal method call in Ruby So the method call we're going to be looking at is this display strings method. You can see it's very simple It's got two local variables find inside it and it is essentially just outputs a combination of the two And what I want to do now is I want to take a look at what happens on the stack when display strings is called so When we call it like this what Ruby does is it creates a stack frame for the display strings method as shown over here It then pops all the local variables and any arguments past to the method onto the stack There's three dots here to indicate some other housework that needs to happen, which isn't important right now This SP by the way is just a stack pointer and Then Ruby also creates a special slot in the stack frame Now this special slot is used to keep track of whether a block was passed when we call our method And if you think about it when you call a method with a block in Ruby You're essentially just passing that block as an argument to the method call And so the fact that it gets its own slot on the stack frame kind of makes sense In this particular example that you'll see we are not actually calling display strings of the block And so the special slot is going to remain empty But what Ruby does do is it sets its own environment pointer to point to the special slot in the stack frame Now this environment pointer is related to but slightly different from the one I had on this screen when I spoke about blocks so this environment pointer property over here is Specific to the block and as we'll see in a minute it actually gets the value of Ruby's current environment pointer But that value then is static and it gets saved on for the block and it's not going to change for as long as the block exists this environment pointer here is Ruby's environment pointer and that changes as the as your program executes and as whichever method is busy executing changes Right, so this is everything that happens during a normal method call in Ruby So let's take a look now what happens on the stack when we call a method with a block So the method call I'm going to be looking at is this one over here You'll see I made a small modification to the display strings method in that I've got a call two times inside it which you see takes a block and That uses the two local variables inside it So just to be clear the method call on the stack I'm going to be looking at now is this call two times Which takes a block? So here is the stack as we had it before while display strings was busy executing So again, we pop the local variables onto the stack Here's the special slot stack point has been set and Ruby's environment point has also been set So this is everything we had before Now this method is busy executing and Ruby gets to the point where the times method needs to run This is another method call So what happens is a new stack frame gets created for that method call over here Again, there's there's all the space for the local variables, etc. It of course also has a special slot But this time we're calling times with a block And so what happens now is that Ruby creates the block object on the heap Remember the block is an object in Ruby and so it goes on the heap because that's where objects go There's also something interesting about this which was pointed out to me recently in that in Ruby 2.2 This block gets allocated on the heap when it passes an argument in Ruby 2.3 upwards There's been an optimization and it looks like to me that in fact the space doesn't get allocated on the heap until the block It's accessed for the first time. So that's a slight difference between those versions Either way Once the block has been created the value of Ruby's current environment pointer gets copied into the environment pointer property of this block and The special slot gets set to point to this block on the heap Okay, so that's passing block is argument done now time starts executing and as soon as the yield statement gets hit the block code needs to execute and What Ruby does to execute block code is it creates another stack frame on the stack for the block it does all the usual things such as popping local variables arguments, etc. into that stack frame and This stack frame also has a special slot and Ruby adjusts its environment pointer to point to this special slot of block now Now you'll notice when I did that I didn't actually delete the old environment pointer I had renamed sorry I renamed it to previous EP and the reason I did that was because in the background Ruby creates a kind of ladder of environment pointers as you see here and That gets used every time you try and access a local variable to find outside the scope of your block and maybe even in surrounding scopes that are nested around your block inside your block and Essentially, it does that by starting at the blocks environment pointer property in this ladder and it travels down this ladder looking for the local variables you trying to access Now I've kind of simplified the process a little bit there's quite a lot more that needs to happen such as various block properties needing to be copied from the heap onto the stack frame of the block and But that isn't important right now The point is that it's this ladder of environment pointers that allows you to access local variables to find in Scopes around your block inside your block and this is called dynamic variable access by the way okay, so This explains why we can access local variables That we're defined outside our blocks inside our block But why can we access methods to find outside of our blocks inside a block in other words Why does this bit of code here work? where basically We defining the method string and then using it inside a block This can't work by the same mechanism Because if it did then my initial aspect example Which defined the test index helper method and then used it inside nested blocks probably would have passed but we know it fails and To understand how this works. We need to take a look at the Ruby block object again So here it is with its our second environment pointers and it turns out this block object has another really important property called the cell property and This cell property gets set to whatever object was active when the block was created So you can see it really as pointing to whichever method was or the owner of whatever method was busy executing when the block was created You can see it as getting the value of whatever self was when the block was created But the point is that it's a self property that allows us to access methods and values of the object That was active when the block was created inside the block And I can show you the self property in action in some live code so what I'm doing here is I am defining the block tester class and as You can see hopefully As you can see, it's a really simple class It's got the block funk method defined in it and it essentially just yields to whatever block you pass it And now I'm going to define my block my my class which is another class and you can see in particular it's got This test funk method which is of interest and what we're doing there is we are defining a new block tester instance and Then we are calling block funk on that block tester instance And we're returning self from inside that block because the point is I want to see what self is going to be Pointing to in this block this self will actually be the return value of test funk Now when I look at this code I kind of intuitively almost want to say that self is going to be test object because that's what it looks like to me But let's take a look at what the actual value is by running this code So first I'm just going to create an instance of my class That gives us that and now I'm going to call I'm going to call test funk on That instance and you can see the value that was returned by that method is in fact our original instance of my class In other words what this is saying is that self in this block is actually pointing to the owner of test funk Which is our instance of my class and that is consistent with what I said before What's interesting about this is that we also know we can intuitively actually call method one inside this block And it turns out the reason we can do that is because this self property over here is actually pointing To the owner of test funk, which is our instance of my class and then obviously has method one defined on it Okay, I'll give an everything I just said I kind of would have thought I kind of would have thought my original aspect example should have passed because here I'm defining test index and we now know that's a helper method and you'd think our spec would be smart enough to add this method to whatever our spec object is active inside this it block and that should mean that Inside this first block the self property is going to point to that aspect object Which means a self property inside the second block should also point to that aspect object Which has test index to find on it and therefore the coach would work but we know it doesn't and When we take a closer look at this bit of code over here, what's happened We see that actually the first block is being created and passed to a method called class evil Now I know none of you are there But about a year or two ago I gave a talk on item classes and in that talk I had this slide where I went on and on about how important it always is to keep track of what self is going to be inside the block when one calls class or instance evil on an object and what I said was that For class evil Self will always be set to the class of the receiver inside the block and In other words what the slide is saying is that class evil is different from normal methods that take blocks Because self inside the block for class evil will not be set to point to the currently active object It's going to be set to point to the class of the receiver and So in this slide what this means is that self inside the first block is going to be pointing to the class of quadruple page and That means self inside the second block is also going to be pointing to the class of quadruple page And I'm guessing there's no method called test index to find on that class and You can see there's also no local variables by that name anywhere in scope and that explains why this example Failed so yeah, this is a little bit embarrassing considering all the hopping on I did on the topic a year ago But I think what everything I just said also explains is why this modification that I made to my aspect example made it pass Because if you recall what I did is I created a local variable and assigned the test index to that and We now know that it's via the environment pointer ladder That this inner block has access to any local variables in the surrounding scope of that block and that explains Why this example passed when I made the small modification and used the local variable instead of the test index method Okay, so that's all I'm going to say about this aspect example today It's time now to move on to use of blocks in the Ruby programming language Which really lent some elegance to the language I believe and that it's its use in the find method Now You may or may not know that there are two main ways in which to define methods or define instance methods at least in Ruby The first way is to use the def keywords as is done in the first paragraph And the second is to use the find method as is done in the second Now the difference is that whereas the second paragraph actually works The first one does not and the reason the first paragraph doesn't work is because def is what they call a scope gate in Ruby Essentially what that means is whenever you use def you're going to lose access to all the local variables defined in the surrounding scope And so when you run the method defined in this way Ruby is never going to be able to find string one or string two and the method called is going to fail However, you'll notice that the find method takes a block and Actually, what it does is it defines the display strings instance method in such a way that it actually Runs the block code every time display strings is called and we now know it's by the environment pointer ladder That this block has access to any variables defined in the surrounding scope Which means display strings defined in this way We'll be able to find strings one and string two and will execute fine when you run it Now you may ask given its relative elegance Why not just always use the fun in define method and forget about the def keyword completely? Well, it turns out that creating a block and running it does not come without without its overhead So you marry may recall this slide that I had where I showed what happened when you called A method with a block we needed to create the block object on the heap copy the environment pointer value into its environment pointer property set the special slot to point to the object on the heap and Then every single time yield was run was hit We needed to create a new stack frame stack pointer needed to move Environment pointer needed to be adjusted to point to the special slot The old environment pointer value needed to be saved down to create this kind of ladder And there was other housework that needed doing as well such as various properties on the heap In the block object needing to be copied to the stack frame and Everything I just said more or less summarized in this gray block needs to happen every single time yield is called And this particular example needs to happen ten times, but as you know, this could need to happen hundreds or even thousands of times And so yes blocks when they run can be pretty slow And it's because of its use of blocks that any method defined using define instance method is going to be quite slow when it runs And as you see in a minute when you speak about lambdas, you will see that they can be quite expensive in terms of their memory use as well Now you might may ask how slow exactly are blocks? Well, we can check this in our code again So here I'm going to benchmark two loops the first one as you can see is a simple while loop It iterates 10,000 times and adds one and one together and We see that that takes roughly that amount of time to do and now I'm going to benchmark exactly the same thing but this time I'm passing a block to times instead and The difference isn't that obvious it depends this come I mean testing things this way is a little bit sort of volatile But in most cases of me trying this the general result seems to be that actually Running the code using a block and passing that two times is more or less twice as slow as doing exactly the same thing using a while loop in Ruby and so it's Obviously if you care about the speed of your code and obviously in Ruby and Rails applications We often don't but if you do care about the speed of your code, it's probably wise to try and avoid the use of blocks as much as possible Okay, so I'm I mentioned lambdas just now. Well, what is a lambda if not just a block as a data value? So here's a very simple example of a lambda being created in case you never saw that before You see we pass it a block and I'm using some of the local variables in that block and here I'm doing a simple call on that lambda I think this code makes it quite obvious that the lambdas also an object in the underlying C code for Ruby The object looks something like this. It is called OB underscore proc underscore T It quite predictably has a block property with all the usual things inside it And then as an interesting side note, it's also got a property called is lambda and This property gets set to true when you're creating a lambda and it gets set to false when you're creating a proc using the proc you would instead And that's the main difference between a lambda and a proc in the underlying C code for Ruby. Who would have thought? And then besides these there are also some other properties such as the end valve property, which we will see in action in a minute Now lambdas are blocks of data values. So they are pretty cool It turns out that they are in fact even cooler as demonstrated by this bit of code over here So display strings blank as you can see is a simple method. It's got two local variables But what it does then is it creates a lambda that takes the block that uses those variables and Then this lambda is returned as the return value And as you can see we call this function we assign the lambda to func value and then we do a call and And This bit of code works and if you know anything about how stacks work You'll know that the fact that this line of code actually works is quite amazing Now to show you what I mean, let's take a look at what happens on the stack during this method call So here's the usual stack frame for display strings funk string 1 and string 2 local variables are on there environment point is set stack point is set Now Ruby gets the line of code with a lambda needs to be created and returned and So what happens now is that created lambda is assigned to the funk value variable on the stack But you notice when I did that when this method exited the entire stack frame for this method was wiped off the stack Along with all references to string 1 and string 2 local variables That means they no longer any references on the stack to the string 1 and string 2 objects on the heap Which means they will be garbage collected and can no longer remain available to your program and Yet as I said this line of code here works perfectly and it actually prints out the values for those local variables So how can this be? But to see how this can be we need to take a look again at what happens on the stack and heap Firstly when we create the lambda and secondly when we execute it So here is what the stack looks like As I had it just now. So this is while this place strings funk is executing Then we have the local variables the second environment points have been set Now this guy executes and it reaches a point where it needs to create the lambda and it turns out that what Ruby does when it Creates a lambda is it creates a copy of the entire surrounding stack frame for that lambda and it puts it on the heap Now this copy of the stack frame has a wrapper object around it As I'm showing here, but that's not important. So I'm leaving it off the diagram for simplicity and Once this copy of the stack frame has been created on the heap Ruby can now create the lambda So here's the lambda on the heap It's got its block property inside it You'll see its n-value property is actually set to point to this copy of the stack frame on the heap and Once all of this is done. This is quite interesting is what Ruby does now Is it resets the current environment pointer to point to this copy of the stack frame on the heap? This is quite an interesting situation because usually this environment pointer points to a location on the stack But now it's pointing to a location on the heap And once this is done It's this modified value for the environment pointer that gets copied into the environment pointer property of this block That belongs to the lambda and this lambda is now set that can be returned And so display string spunk exits and the lambda is assigned to the func value variable on the stack Now you'll notice what we have now is we've got a pointer Going from the stack through this lambda object on the heap to this copy of the stack frame on the heap Which has references to the string one and string two variables And so there's a large pointer going from the stack To somehow to the string one and string two objects on the heap some way Which means that they won't be garbage collected and they can remain available to your program and That explains why the lambda can print out the values for these variables long after the stack frame over here Got wiped off the stack So that's everything that happens when the lambda is created Now let's see what happens when it gets called well all that happens is the block code needs to execute And so we know that when block code executes a new stack frame is created for the block so here it is and the environment pointer gets adjusted to point to the special slot of this stack frame and This copy of the stack frame on the heap is now going to be used as the direct environment in which to execute the block Now you'll notice this means lambdas can be quite expensive in terms of their memory use because as you can see this copy of the stack frame needs to remain on the heap for as long as the lambda exists in your program and You'll notice that any variables That actually had references in this copy of the stack frame will also remain on the heap for as long as your lambda exists in your program And so if you're not careful what you're doing your lambda can unintentionally cause your program to use a lot more memory Obviously also the more lambdas you create the more expensive your program can become in terms of its memory use But Ruby has found a way to mitigate this to some extent in that if you're creating several lambdas in the same Environment Ruby is not going to create multiple copies of the stack frame It's rather going to use the same copy of the stack frame on the heap And it essentially does that by checking whether the environment pointer already points to a location on this on the heap Rather than to a location on the stack Okay, so I know the longer you look at this diagram the more you kind of feel like you've seen it before but I think the point of this diagram is that When the lambdas created there's a copy of the surrounding stack frame created on the heap and When the lambda is called it's this copy of the stack frame on the heap that is used as the direct environment In which to execute the block code right, so Right, so you'll you remember that I mentioned there's a wrapper object around this copy of the stack frame Turns out we've got access to this wrapper object by the binding class and So I can show you how to get access to that with a simple method over here so you'll see what I'm doing is I've defined get environment and Essentially, just I've got two local variables inside this method and I'm returning binding from inside that and Now what I can do is I can get a handle on that binding object As you see over here and then we can go and poke around inside it a bit and You can see that quite predictably. It's got two local variables X and Y defined and It's got the values that get environment had for X and Y and when we defund it way up here somewhere over here and The interesting thing about this binding object now is that we can actually use it in our code So for example, what we can do is we can pass it to evil and we can say to evil Execute this expression X plus Y But use the binding object that are passed as the environment in which to execute the expression and You'll see that it works fine and it prints out the value three even though there's no local variable X or Y defined in the local environment What's interesting about this called to evil is that it's essentially creating a closure because it consists of an expression and Also of an environment in which to execute that expression and that's exactly the definition of a closure Okay, so finally I Mentioned that lambs were relevant when talking about a fine method. Well to see what I mean Let's just take a look at this example over here in particular. Let's just focus on this defined method call so you'll see that It takes a block as I said before and actually what the fine method does is it creates this display strings instance method to be a lambda and So what this means obviously is that creating this instance method and executing it is going to be quite slow Because as you can see there's quite a lot of overhead involved in creating and executing a lambda Again, you may ask how slow exactly is defined method. Well, we can do some more benchmarking So what I'm going to do is I'm going to define two methods the first one using the deaf keyword And I'm going to benchmark how long it actually takes to create that method and hope it works So there I've defined my first method and I'm going to define a second method That does exactly the same thing, but I'm using the fine method to create it instead of the deaf keyword And you can see that takes roughly done that amount of time and we print them out in a sort of more readable format we see that The demo gods are against me today, so let's try that again So at the moment it seems to be only taking one and a half times as long to create the method using the fine method as opposed to using the deaf keyword But often enough it seems to be taking it can take up to more than twice as long to use the fine method And now let's see how they compare when we execute them So here I'm benchmarking calling method one the first method 10,000 times You see it takes that amount of time and I'm calling the second method 10,000 times remember this was created using the fine method instead and We see again it takes almost twice as long to execute exactly the same method, but Rather it was defined using the fine method instead of the deaf keyword So there's a significant performance implication So yes, the method is slow when you create it using the fine method But what it does do is it allows this bit of code over here to work Because you'll notice what has happened is we've again got a method with local variables Which are then used inside this block But we now know that once defined instance method exits string one and string two will be wiped off the stack And will theoretically not be available to this instance method anymore But because this instance method has been created to be a lambda We now know that there's a copy of the stack frame that has been created on the heap and Hence this instance method over here will be able to find string one and string two long after the fine instance method has Exited and that's quite a good thing because instance methods do tend to stick around for the duration of our programs Okay, and that's all I really got to say today Here are my details. I'm code kitten on Twitter Epidio on GitHub a lot of the more technical technical explanations I gave today came out of this very awesome book called Ruby under a microscope and I work for a company called zapy store, which does some pretty awesome market research software using Ruby and blocks extensively Thanks for that