Vous êtes sur la page 1sur 4

>> [music] In this segment, I want to show you procs, which are a lot like blocks.

Except procs are actual objects and have all the power. Of function closures and I want to do this to demonstrate an example of what it means to be a first class expression in a programming language, so lets go back to talking about blocks with the B as an boy and remind you that they are different, they are not objects almost everything in Ruby is an object But blocks are not. Because the only thing you can do with a block that you are given when someone calls some method you're defining, is yield to it. You can yield to it to call it in as many times as you want. But you cannot return it, you cannot store it in an object, you cannot put it in an array or anything like that. Now there is a way to turn blocks into objects, and that's what I'm going to show you in this segment, but what that does is that it creates an instance of a class called proc with a p as in peter. And then that object has a method call that you use to essentially invoke the code and call the closure. So in a programming language, we say something is a first-class expression when it can be the result of a computation. It can be returned by a function or a method. It can be stored in an object and it can be passed around just like numbers and objects and anything else we have in our language. And if you cannot do that, then we say it's a second class expression. So, in Ruby, blocks are second class. They're not really expressions. You can't put them where you put expressions, but instances of the Proc class are first class. So that's the distinction. And now, I just need to show you how to make these Proc objects. And this being Ruby, it turns out there's several different ways. I'll just show you one. And that is that there is a function in the object class. So, it's available everywhere. It's actually part of every class's definition. And, believe it or not, the name of this method is lambda. Lambda takes a block.

We given a block, just like we could pass a block to any other method, like each, or map, or times, and it returns an instance of proc. And it does it via one of the other ways that you can make other instances of proc in the language, which you can learn on your own if you're curious. So once we have that then we have this object that we can treat absolutely as any other object and then call it just like you would use a closure. So let me show you an example of where that is a little useful, and let me start by showing you why you don't usually need this. So suppose I had something like an array 3, 5, 7, 9. If what I wanted to do was map across that array some computation like add 1 to every element. I would just do that with a block. I don't need a first class expression to do that. That's how blocks work very well in ruby and so I would just get back an array b that's 4 6 8 10. And if I wanted to then count, this is a method I don't believe I've shown you before. This takes a block and counts how many times when it's called on all the elements in the array it returns true. So if I say, how many times is x greater than or equal to 6 on the array b, then I get 3, because it's true for 6 and 8 and 10, and it's not true for 4. And I don't need any first class functions for any of this. But suppose I wanted to create an array of closures. So, what I want to do, but it's not going to work, is to create a third array, C, that contains. So I want a map across of it. But then, what I want to put in each array position is a closure, is a block, and this is what doesn't work. That says x greater than or equal to y. So what I want to do, is, I want an array where the ith position is a little function. It takes in argument y and returns true if what was in a at that position is greater than or equal to the argument past it. And this just won't work. I'm going to get a syntax error here because Blocks can't do this. You can't put a block here, we need an expression.

But I told you how to turn blocks into objects. I mean, just write lambda. This is just a method call, and so I'll put unnecessary parenthesis in here. The result of this method call is an object, and so now c is an array. It has a size, it has four elements and each element is an instance of the Proc class, and it, the REPL is printing it in this funny way. So, once you have an instance of the Proc class, what can you do with it? You can call it. If I do this, I'll get an error message. Because the, Proc I created there expects one argument, but if I pass in something like 17, then I'll get false, because, what is in there, what was in the second position, which I think is an 8 is not greater or equal to 17, but if I pass in 7 then I get true. So now, what I really have in c is an array of closures that I can use via the call method. Alright, so now, I can take that array and I could count how many times if I take what's in the xth position of c and all it with 5 I get true and the answer is 3 times because 6 is greater than equal to 5, 8 is greater than equal to 5 and 10 is greater than equal to 5 and if I did this with 50. I would get zero. So that's what you can do with first-class closures that you cannot do with blocks. So what's the moral of the story here? The moral of the story is that first-class closures, these things with, that I call procs, P as in Peter, are more powerful than blocks. They are first class expressions that you can really use anywhere even store in data structures. This is what you want for idioms like call backs. But it turns out that blocks, with b as in boy, are more convenient in the common cases, just when you're calling map or count or collect or select or whatever. So this helps us understand what first-class means which is often something people don't understand when in programming languages people talk about it. And it raises an interesting language design question. Why did Ruby do this? Why did they go to this trouble of making these second-class blocks so convenient

that we couldn't actually use them as closures and then have to create a separate thing. The thing that we can create with the, the method lambda would then have the full power of closures and, and it's a tradeoff. It's a question of when is it worth it to make the common case more convenient at the expense of having to learn something different for when the common case doesn't quite meet your needs. And most languages simply provide first class closures as the only thing, and try to make them as convenient as possible. Ruby made a slightly different choice and thought it was interesting to walk through the distinctions between blocks and procs.

Vous aimerez peut-être aussi