RubyConf 2015

Solucionando los problemas de SystemStackError en las aplicaciones Ruby

Danny Guinther  · 

Presentación

Vídeo

Transcripción

Extracto de la transcripción automática del vídeo realizada por YouTube.

- Good morning everybody. Going to try to start just a few seconds early because chances are I will go over time. But I'd also like to give you guys an opportunity to ask questions in the event that you can't read any of the slides or anything like that. Be able to shout at me and say, "Hey, could you read that for me because.

. . " Lots of good stuff. All right. So the first thing I want to ask you guys is how many of you guys went to Aaron's keynote yesterday? Nice. That's great because I was so psyched about his keynote because it was such a great introduction to a bunch of things we're going to talk about today.

So without further ado, let's do that. So today, my presentation, as you all guys know, clearly, because you're all here, is A Muggle's Guide to Tail-Call Optimization in Ruby. I'll get into what I mean by that a little bit more in just a second, but first let's consider some alternate titles I was thinking of.

Harry Potter and the Well of Eternity. Because systems back errors can be a nightmare especially those back traces that go on for days. And just kind of wanted to get this out upfront. Harry's a parseltongue, and his scripting language of choice is probably going to be Python, not Ruby.

So if we can start to kind of come to terms with that now, that'd be great. So, kind of actually in that vein, I want to also give you a warning. Maybe not a warning, but like for whatever reason, this topic like I guess quite a few topics in our industry, gets pretty religious at times, whether it's like Bem or Emacs.

In this case, we run into that divide between functional and object oriented languages. So if you'll indulge with me for a moment, I'd like you to imagine if you dare a world without Minaswan. And for you guys who don't know what Minaswan is it stands for Matz is nice, and so we are nice.

I don't know where that picture came from. I actually can't find it on the internet any more now that I found it It's Matz with a Matz puppet. What the hell? All right, so, from the blog of Guido Van Rossum, who, for those of you who may not know, is the creator and inventor of Python, so back in 2009 there was a lot of talk going on about tail-call optimization.

Here are just a few select quotes, comments from his blog related to it. "How very pythonic of you to make up stupid reasons "for not implementing a very simple optimization. "This is very pythonic because it shows "poor decision making, poor performance, "and immature ideology.

" So very clearly like somebody who like kind of more functional type things and just can't believe that Python is not going to include it. Total opposite end of the spectrum. "Refreshing that you stuck with your intuitions "rather than submitting to these TCO-requesting "functional fiends.

" It blows my mind a little bit that a language feature can insite so much argument. But that's a The good news is no matter which side you are on in this particular matter, because it doesn't matter, you're going to be right. Because everything, it's all about your point of view, right? So as Obi Wan will tell you here, It's all Everything kind of depends on your point of view.

I also should warn you there's a few Star Wars references in here despite the Harry Potter theme of this talk because I am so excited for next month. But, ah, stay focused. Stay on topic. Move along. So, all right, good. I'm glad you guys laughed because somebody was threatening that I would get a twilight crowd and I am not prepared for that.

So. What the hell is a muggle? So for those of you who may not know, a muggle in the Harry Potter books is someone who lacks magic ability. Now if you're wondering why you care about this in this particular context, the way I want to present this talk is without magic.

And by magic, I kind of mean like, I think you most often hear it with Rails, like Rails magic. It's doing all these magical things behind the scenes for you, and on the other side of that magic emerges something wonderful. But you have to suspend disbelief in that middle process.

But if you're one of those people who loves magic, I don't mean to exclude you either. That works. But it's going to be up to you to decide kind of where the line between knowledge and magic fall. Because as much as I'd like to explain to you every minute detail of this, we only have so much time.

And I just can't do it. So, let's get down to our subject. So, what is a tail-call? Now if when you hear the term, tail call you think about certain types of phone calls that happen between midnight and three a. m. in the morning, I'm going to need you to put down the Bud Lite Lime, focus, and let's do this.

So, kind of definition dictionary-wise of a tail call is a subroutine call performed as the final action of a procedure. So that's a little bit terse. So why don't we like look at this in action? So here's kind of like your canonical example. Mostly canonical because it is just about as simple as can be.

You have this method, a call in tail position, and you have another method inside of it that is very clearly the last thing that the outer method does before it is complete. To contrast that with kind of your canonical counterexample, you have another method, not a call in tail position, which calls other method and then adds one to it.

So this kind of defies that definition we looked at because other method is not the last bit of action that is happening in this method. You have to still add one. And I know there are some clever folks among you who are thinking, "Ah, but what if we do "one plus other method?" Still not a tail call because again it's not necessarily that it has to be the last thing at the end of the line or on the last line.

It really just needs to be the last thing that happens in that method before it's done. And in this case, both cases, once the result of other method comes back, we still have to add one to it. So the kind of interesting thing about this is it means there are very certain circumstances in which you can make a tail call.

So some examples of those types of, they call them tail call saves, are some of these. So in this case we have like in the middle of a method, not even the end, kind of behind an if statement, we have this return sum call. This is actually a valid tail call because it's attached to return.

So really the last thing this method does is this call to sum call. Another one here kind of like those counterexamples we just looked at is this call with an expression inside the arguments. So this is different than the one we looked at before because by the time we actually call other call, the expression my int plus one will have already been evaluated.

So other call will really be our last operation there. You can also attach it to boolean operations, so you have false or other call. That would work, as well as true and other call because in both of those cases that other call's really just going to be the last thing that happens in the method.

And a final example here, and kind of what gets us into some of the real power that comes with from tail call optimization is this recursive count call, which really just recursively will keep calling itself until it gets down to zero. So you kind of get like a five, four, three, two, one, zero type thing.

Again this one I think is a little bit closer to that first example we looked at where it's not too complex. You can really see that recursive count is the last thing, the last operation that will happen in this function before it returns. And there are many more, which I will be happy to talk about later if you're interested.

So let's take a moment here to pause and reflect on recursion. So if we were to look at that recursive count we were just looking at again, you can kind of see that the output of this can be, as I said, five down to zero. And if we unwind the stack, we can kind of see the recursive count gets called, it puts five.

Checks to see if that's zero. And then calls itself again with four. And it continues all the way down until you have your base case, where you'll hit zero and you'll exit it afterwards. When you have recursion plus a tail call like this, you end up with what is tail recursion.

And so it's a special kind of recursion that's particularly useful when combined with tail call optimization because it allows you to do some really neat things from a kind of like functional perspective. Like if you're familiar with Church's lambda calculus one of the things that it was able to take advantage of is this kind of like tail recursion to actually make it so it needed really fewer operators in some of the modern languages that we use today.

[ ... ]

Nota: se han omitido las otras 4.144 palabras de la transcripción completa para cumplir con las normas de «uso razonable» de YouTube.