We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Reducing Enumerable - An Illustrated Adventure

00:00

Formal Metadata

Title
Reducing Enumerable - An Illustrated Adventure
Title of Series
Number of Parts
66
Author
Contributors
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Meet Red. Red is a reducing lemur, and he loves to sum things using the reduce method. The problem is, with Ruby 2.4+ and the sum method he's starting to think reduce isn't that useful anymore. Distraught, Red asks his master for advice, and she sends him off on a grand journey to learn the true powers of the reduce method by reimplementing various methods from Enumerable. Join Red on an illustrated adventure through the land of Enumerable as he learns to map, select, find, and more using his trusty reduce. If you're new to Ruby and Functional Programming, this is the talk for you.
Adventure gameVideoconferencingTwitterReduction of orderLattice (order)Musical ensemblePoint (geometry)MultilaterationBitException handlingLevel (video gaming)Reduction of orderHill differential equationEnumerated typeNumberElectronic mailing listFunctional programmingHorizonPoint cloudWeb 2.0Default (computer science)Functional (mathematics)Moment (mathematics)TwitterPresentation of a groupPower (physics)Instance (computer science)Adventure gameCodeService (economics)SummierbarkeitElement (mathematics)Multiplication signMappingForestSystems engineeringStack (abstract data type)Water vaporGreatest elementSlide ruleSeries (mathematics)Transformation (genetics)Physical system2 (number)JSONXMLComputer animation
Reduction of orderSystem callFunction (mathematics)Level (video gaming)Element (mathematics)Selectivity (electronic)Electronic mailing listElement (mathematics)ResultantAreaMultiplication signBlock (periodic table)Functional (mathematics)NumberEntire functionComputer-assisted translationSystem callType theoryBookmark (World Wide Web)Network topologyReduction of orderBranch (computer science)Optical disc drivePointer (computer programming)Point (geometry)CASE <Informatik>Parameter (computer programming)Object (grammar)BitLevel (video gaming)CodeSign (mathematics)Slide ruleSurjective functionComputer animationPanel painting
Element (mathematics)Function (mathematics)Reduction of orderSystem callCountingReduction of orderElement (mathematics)Software developerWave packetFunctional (mathematics)CASE <Informatik>Parameter (computer programming)Default (computer science)Electronic mailing listCodeMoment (mathematics)Set (mathematics)Computer clusterBitPiLevel (video gaming)Enumerated typeKey (cryptography)Control flowSystem callHash functionSelectivity (electronic)WordTwitterSoftwareOptical disc driveLibrary (computing)Computer animation
Function (mathematics)Reduction of orderElement (mathematics)Software testingTwitterStiff equationTape driveElectronic program guideCountingMereologyLevel (video gaming)Functional (mathematics)Multiplication signElement (mathematics)Arithmetic meanDifferent (Kate Ryan album)Loop (music)HypermediaWordEnumerated typeSlide rulePower (physics)InformationReduction of orderElectronic mailing listCategory of beingStiff equationGraph coloringTape driveBitVariety (linguistics)Group actionHash functionResultantClosed setLattice (order)Goodness of fitElectronic program guideAdventure gameException handlingMoving averageRuby on RailsSelectivity (electronic)MappingPanel painting
Coma BerenicesMusical ensembleXMLComputer animation
Transcript: English(auto-generated)
Looks like we're about ready to go. Now, I cannot promise cartoon raccoons,
but I can promise cartoon lemurs, and I swear they're just as good and just as fun. So, just because this is a magic talk, and I enjoy a little bit of theatricality magic, we brought ourselves a magic book along. Now, you might wonder what the magic book happens to be for. Well, you see, every time I turn one of these slides,
slide happens to turn. So, who exactly am I? My name's Brandon Weaver. I am an artist. I ended up becoming a programmer. How that happened was a series of unfortunate accidents which started with getting into web design, which, yes, a little bit of HTML CSS
makes you more marketable. Okay, a little bit of JavaScript. You just add a little bit of animation here and there. Sparkle a little bit of this. Okay, that seems insane. Now you need to back and wait a second. I know where this is going. I don't like this anymore, and the next thing I know, I'm doing systems engineering, so that is a thing. And currently, I'm doing that over here at Square, where I am an infrastructure services engineer
on the platforming team, amusingly working on the same code that Jack Danger happened to mention in his talk. But that's a little bit of fun. So, as far as social networks or anything else, you can find me on Twitter, GitHub, Medium, IRC. Yes, people still use IRC, I know, right? And Ruby.social,
which is one of the new Mastodon instances. And you will notice that I left tags to my Twitter on the bottom of a lot of these slides, so you will be able to find it later, and I will go back over this at the end of the talk. So, shall we get started then? This is Red. You see, Red is a magical lemur,
and he loves to reduce things. Just absolutely adores it. And he could take stacks of numbers all day long, and he just loves it, and reducing them into sums. To him, it's the most amazing thing ever. So, let's take a look real quick into how reduce works.
So, reduce is taking a list of numbers, like let's say one, two, and three, well, for this example, we'll get into more later, and reducing it into the number of six. And what this might look like is something like that,
but that is a bit hard to read, and especially if you don't know what entirely it's doing. I know I certainly didn't for multiple years, and I probably still don't in some case, but we will ignore that part. So, let's take a look into what it's actually doing here. Reduce starts with an accumulator, which you'll see in red and underlined there
for the color-blind or otherwise. And an accumulator is often an empty value. If you add anything to zero, you're gonna get back that number. One plus zero, one. Zero plus one, one. One, one, well, that one was easy, but that means that if we have an empty list, we actually have something we can return as kind of the same defaults.
Next, we have the actual list, which you'll see here in, would you call that cayenne or more of teal? No, honestly, I'm not sure. We'll go with teal, I like teal. And that's gonna be present throughout this talk as V. And then the last, and potentially most important, is how do we join the accumulator and that value together, which we'll have in green
as our way of joining things together? So basically, number plus a number is going to give you back a number. So it ends up looking something like this. Zero plus the list of one, two, and three, or in a little bit more common parlance, something kind of like that. So let's take a look into what this is doing
step by step. So we start out with an accumulator of zero. And with that, we add the value one, and that's going to give us back a new accumulator of one.
So every step of reduce, the accumulator carries over and becomes the accumulator for the next step. So if we go to the next step, the accumulator is now one and we add to that the next value in our list, which would be two, and that's going to give us back the value three. Which means our last time around, we have three plus our last value, which is three,
which means we ran out of values, which means reduce now knows it's done and it can return that accumulator, which is six. So of course, by now this means that we have a list of many things and we reduce it into one thing using an initial, often empty accumulator value, such as zero,
and a way to join two values together. Of course, this makes us masters of functional programming. We figured out everything there is to do here. There's no point in really learning much of anything else. We know this, we've already got it down. Well, the problem is, except Ruby 2.4 came out with this interesting little function,
which I know some of you are definitely thinking about as I did this, and that function would be sum. So I guess my talk's kind of pointless now, isn't it? Well, that raised the question, is reduce unnecessary? So I wouldn't say it's the end of the story because Red decides to do something.
He decides to ask his master, does sum kill reduce? And then something magical happens. Red gets back a letter, and in that letter he found, his master had replied to him and said, come visit if you wish to learn.
So it looks like we're going on a little bit of adventure to find the true powers of reduce from Red's master, Scarlet. So Red journeyed over the rolling hills through the grassy plains until he saw a castle upon the horizon, and that castle was nestled between the mountains
where the clouds reached the sky, and there is where he found the great and wise master of reduce, Master Scarlet. So Red told his master of what he had learned, of summing lists together, of using addition, and all the amazing things he had done, but he still had that nagging question on the tip of his tongue, so he just had to ask,
does sum make reduce useless? Ah, Red, consider for a moment, perhaps, that you can do more than just summing with reduce. What if we used subtraction, multiplication, division? What if we didn't use numbers at all?
Perhaps instead we have an empty array and we push to add elements to it. What could one do with this, I suppose? I know just the thing for you. You'll find three masters in the land of innumerable. Go out and learn from them about their functions
and see if you can figure out ways to do the same with reduce. And with that, Scarlet left Red with much to think on, a map to help him on his way. So with that, he was off to the corners of the map to find from the masters how their functions work
and how he might use them with reduce. And now a special guest star, a convenient cup of water. Thank you, you're a good friend. The first master he was to visit was the master of mapping.
So he journeyed through the forest of transformation deep into the groves where the mushrooms bloomed and creeks ran a sparkling blue. There he found a path and the end of the path was a house, and outside that house, he found the first master he was to meet, Master Chartreuse of Map.
Welcome, Red, I've heard so much about you and your journey from Master Scarlet. Wise master, can you tell me how map works so that I may implement it with reduce? Let me show you, young one, the ways of mapping.
To map is to apply a function to every element of a list to get back a new list. So then Chartreuse began to explain map. Shall we take a look? Such that we have a list of one, two, and three, and we wish to multiply every element by two.
That is our function. So each element is doubled. One multiplied by two is two, two by two is four, and three by two is six, giving us back an entirely new list of two, four, and six. So Red began to wonder, how would you apply this to reduce?
His new list was empty, and his joining function was pushed, so how might we use this? Well, you see, what we start with is we push on a new element to the list for every step that we go about, but before we do that, we call a function
to transform that element into what we want it to be. So taking a look at this all together, it might look something like this, but that's a lot of code, and personally, I find it very unsettling as well. Yes, I agree. So let's dig into it and find out
what exactly this is doing. You see, we have our old familiar list, which is going in as an argument here, and for each value, it comes across as V, and then we have our accumulator, which is now an empty array, and that is going to be there as A.
And next, we have our joining function, which in this case is push. If you use push on an array, that means that you add a new element to that array, but before we add it, we happen to call the function that we were given with the value, effectively transforming it before we do anything to it. So the idea here is that we're pushing
onto our accumulator the result of calling a function on a value, which is a bit of a mouthful, I do agree, but we'll take a look at what exactly that's doing. So something like that might be called like this. Now, you'll notice that instead of enumerable methods,
this is called using a list, and the function, which is a block in Ruby, is still on the outside much the same, and we still get back the result to four and six, but how exactly is that working? So let's take and break that up real quick. So we start with an accumulator that's an empty array,
and we push to that the result of one applied to our function, which is basically the same, saying call or multiplied by two, which gives us back a new list of two. And now, we start with the list of two, and we push onto that the result of two multiplied by two,
which gives us a list of two and four, and finally, a list of two and four, to which we push the result of three multiplied by two, which gives us back our final list of two, four, and six. So to map is to apply a function
to every element of the list to create a new list. To map with reduce is to apply a function before opening an element to list in the first place. With lessons he learned from map, it was time to visit the next master, select, and see what there was to learn. But on his way, he found a very peculiar tree,
and he's starting to get lost as things seem to go backwards, forwards, and he had no idea which way was up anymore. And on the ground, he found a hat. Now, you see, with the lemurs, hats meant that there was a master somewhere in the area. I mean, only masters wore hats, surely. So Red picked up the hat and wondered aloud,
is there a magician? Is he here? And then, the tree reached down a branch and said, well, hello there, would you be so kind as to give me my hat? Are you a master? Well, yes, I am. I'm Master Branch. You see, I get blamed the cat for knocking it off again.
It was probably trying to cherry pick and couldn't commit to it. Wait, wait, wait, wait, no, come back, come back, come back. It was about at this point that Red had noticed the hastily scrolled off beware tree sign. Now, with the lessons he learned from map, it was time to actually go to the master's select
and hopefully not find any other oddities. But unfortunately for Red, the master select was nothing but oddities. He journeyed through towns and villages looking for the master select, but as he got closer, things kept on getting stranger and stranger until there were eventually nothing but absurdities all around him. And there, at the end, he found a house,
and in that house, he found the master of select. And when he found Indigo, the master of select, he found it to be quite eccentric. Select had him with a collection of various Ruby arts and toys. But Red had noticed something peculiar in both the tree and around select.
There was a cat, so he asked Indigo, is that a Cheshire cat? Ah, no, no, no, no, we're not in Wonderland. We don't call him a Cheshire cat. We call him an Escher cat here. So Red, obviously a little bit disturbed by this, decided to keep on going with what he was normally going to do.
How do you find anything in this collection? Ah, why with select? You see, I can find all the Rubies in the entire room like this. I just have to zoom around, and there, we're done. So Red decided to ask, why is master? How may I implement select using reduce?
So then Indigo decided to show him. Let me show you a magic trick. I take a number in and a function, and if the function isn't true, well, poof, it's gone. I'm gonna be seen again. So Indigo began to explain. Let's take a look real quick.
Select uses a function to decide which elements should go into our new list. Such that we have our favorite old list, one, two, and three, we wish to only get the even elements. That is our function. For one, it's not even, so we don't want that. We get rid of it, no. For two, it does happen to be even,
so we keep this element. It's exactly the type we're looking for. And for three, no, no, no, no, no, no. That won't do it all, which means that we get back simply just a list of two. So Red decided to take a look into this and see how he might implement select using reduce. So like map, we use a function,
but instead, we're using the function. Whenever we decide to push an element onto a list, we only do that. If the function happens to return a truthy value, which gives us something like this, but you might notice something odd here. We have to return the accumulator after this,
and that's because if you happen to use if, and that returns nil, well, reduce doesn't like nil. No one really likes nil. I don't like nil. Nil gives me nightmares. But one might say also, you should use each with object. Well, each with object does not fit on slide, so here we are.
So essentially, what we're doing is we're pushing a value onto the list if it happens to return true when given to that function, and then in any case, we're returning that list, which means we have a function like this, which might be called a bit like this. This looks very similar to our map example from earlier
where we have a list of one, two, and three, and we're selecting even numbers, which gives us back a list of two. So let's take a look into how that's working real quick. We start with an empty array as our accumulator, and we push onto it the value one if it happens to be even. In our case, this function is checking if the number's even.
And since it's not, we get back an empty list. In our next case, we take an empty list and we push onto it the value of two if that happens to be even. And since it is, we get back a list containing two. Now, we start with a list of two, and we push onto it the last element, three, only if that happens to be even, which means that we only get back a list of two.
Which means that select is to use a function to decide which elements belong in a new list, and to select with reduce is to use a function to decide whether or not to add the element to the list in the first place. And with that, we're headed on our way to our final destination, find.
But find is quite a way. I mean, just look at that map. That's a bit excessive to walk, don't you think? We're not gonna be mean to red. We're not gonna be nearly that mean. So we drew a train for him, and for some reason, the train had taken on the name the Ruby on Rails, and he had no idea why that was. But in any case, it was a train,
and it was quite comfortable. So with that, red was on his way to the master of find. And as he journeyed along, he eventually saw the city of find, Violet the master, had constructed all these amazing things with all the research and all the things that she had found, and a conspicuously placed teapot
because I have horrible humor. So he left the railway and went into the town, and he found an academy, and on his grounds, we found a vast library, stretching for what seemed like miles and miles, and inside that library, in the deepest of alcoves,
he found his next master, find. And inside that alcove was Violet the master of find, and she was looking for a very specific book as she entered. Ah, so you must be red. Oh, I've heard so much about you. Come in, come in. I'm just looking for a particular book at the moment.
So you look through all the books in the entire library just to find one book? Why no, how silly would that be that I keep on looking for a book after I've already found it? That's precisely the use of find. Could you show me how find works, wise master? Why, of course. Find works much like select,
but once we find what we're looking for, we stop looking. If we don't find anything, well, we found nothing. Now, there are ways to have a default in this, but we won't worry about them today. So then Violet began to explain find. Shall we take a look? Find uses a function much like select to find if an element happens to be in a list.
Such that we have a list of one, two, and three, and we wish to find the first even number. That is our function. So for each element, we check if it's even. If it's not, we keep looking. And if it is, we stop, meaning that we don't even ask three
if it happens to be even, and we stop iteration. Do you know what a break is, young one? So that gives us back the value of two. So Red had to think about this for a while because this was a very strange thing to do with reduce, isn't it? I mean, you're returning one value here
instead of an array like you would normally be. So how exactly does this work? Really, we don't even care about joining or accumulating or anything. We just care if the function happens to return true. So in this case, what we do is we break with a value if a function happens to return true, much like select.
Now break, for those not familiar, is a keyword that allows you to break out of a loop and return a value. But even the example looks nothing like we've seen before using reduce. What is this madness? You see, if we're reducing it to nil,
we don't even care about the accumulator. You mean to tell me that we're basically using reduce like in each loop? Well, yes, essentially. There's no rule against it, though I will probably get dinged on code reviews for it. We'll ignore that. So we have a way to break out of our function of reduce with a value, but only if a function call
happens to return true, which gives us a function that looks a bit like this. I mean, if we never decide to take a break, we're never gonna get anything back. I suppose in the trend of things, that's another metaphor for software development, isn't it? So much like our previous example,
find takes in a list as an argument and a function, and in this case, it will return the value two. But let's take a look at what exactly that's doing. We start with a value of one, and we break only if that happens to be even.
It's not, so we keep going. Next, we decide to break with a value of two if that happens to be even, and since it is, that means that we return the value of two, and we don't even bother with three. So to find is to use a function, locate a single element to list, and then stop looking. To find with reduce is to reduce into nothing
until an element matches the function, then to break out with that value, which is quite a mouthful, I do say myself. So with his journey now done, Red was going back to see his master. But on the way, he ran into another set of lemurs, a particularly odd set, Cerulean, Saffron, and Vermillion.
Cerulean was clapping on his tambourines behind him. Two other lemurs, Saffron and Vermillion, were singing along merrily. Red was naturally curious about this and decided to ask what was going on. What's with the other two lemurs back there? Ah, that would be Saffron and Vermillion.
You see them? I see extensions. They make every trip go a bit faster, but the problem is they never listen to anything you say, unless you happen to play a fiddle. And I have not figured this out yet, but as it were, at least they do listen to that. So why the journey to see Master Scarlet? Well, that's because I'm on a journey
to establish a new school of innumerable, Tallybai. We've heard from the Council of 2.6 that it might be coming eventually, and Grand Master Nobu may well have ordained the code already. Would you be willing to show me what countBai does? Rather, Tallybai, because I changed the slides.
Tallybai works like map, in that it applies a function to a value, but different in that it uses a return of value as a key to keep a tally or counts of something. In this case, true or false. In other cases, maybe the first letter of a word or something else entirely. So then Cerulean began to explain Tallybai. Shall we take a look?
Such that we have the elements one, two, and three, and we decide whether or not they're even. One is not, so we now have one count of false. Two is, so we now have one count of true. Three is not, so now we have two counts of false
and one count of true, which gives us back a hash of true count one and false count two. But that doesn't look like an array. I'll need something new altogether, won't I? So instead of reducing into an array, perhaps we can reduce into a hash.
And for those not familiar, that zero there basically means any key it doesn't know about is going to have a default value of zero, which means we can add to it as much as we want. And then if we want to keep the same style as we did before, we might end up with something that looks like this. Whoopsie, going back. Now, that terrifies me.
I want to never see that code again, so we will make it go away, because I'm pretty sure it scares the rest of you too. So we'll cheat a little bit. Ruby is not technically fully a functional language, so we can get away with a few things we're not supposed to. In this case, what we're doing is we're calling a function on a value to get back a key. And then with our accumulator hash, what we're doing
is we're taking that key and we're adding one to the count to that. Now we can take a look at our tally by function, but as always, this is a bit complicated, so let's break it up. So remembering back, we first find our key, which is kind of like map. We're applying a function to a value to get back a new value. And with that, we're taking our new hash
and we're adding one to the counts of that key, so it could be something like word.first, or rather word zero, because we're in Ruby. And all together, our function might look a little bit like this, but that is still very dense,
so let's take a look into what exactly it's doing. So like much of the other functions, it takes in a list and then takes a function, and with this function, it tries to decide the counts of elements. So in this case, and you will forgive me because slides are such a precious commodity of resource, we're gonna cheat a little bit. We're going to have no counts to start with,
and then we're going to have the value one, which is not even, so it's false, which means we add the counts of false one, which gives us back new counts of one element of false, which means the next loop around, we start with a count of false of one, and we have element two, which is true,
which means we add one to the count of true, which means we have one count of false and one count of true. And then finally, we have one count of false and one count of true, and our last element happens to be false whenever the function is applied to it, which means we get one more count of false, giving us back a final count of two and one.
So tally by is counting the elements of a list after you apply a function to them, kind of like map. And a tally by reduce is using a hash to keep counts of values transformed by a function. After saying farewell to Cerulean, wishing him luck on his meeting with the Council 2.6,
Red found himself back where it all began, back where it all started. So Red told Scarlet of all the things he had learned and seen over the time he spent in the Land of Innumerable and all the adventures he'd had. Just look at all the new functions I've learned to make. But I still have to ask, even after all of that,
I've only re-implemented functions which already exist, haven't I? Does this mean I should use reduce for everything now or just reduce unnecessary? There are yet so many fascinating lessons out there to learn, Red, but this was but the beginning of a grand journey for you, a grand journey of knowledge.
Consider with me for a moment, would you use an ax to trim a bonsai tree? Well, no, that wouldn't make much sense at all. And would you use a pair of hedge trimmers to cut a mighty redwood? No, does this mean I get pruned?
Quiet, you. The challenge, Red, is knowing the difference between the two and knowing when to use each one wisely. So, too, are the ways of reduce. It has its uses when simple functions won't do, but that doesn't quite answer your question, so let's take a look into some of the power of reduce
that might be beyond what you've seen already. And there is true power here, young one, but power we must learn to use properly before we're able to use it correctly. There are parts of composition, currying, closures, transducers, category theories, and more beyond your wildest imaginations.
That's precisely what makes reduce so much fun to learn and use. Consider with me that we might be able to take a function that reduces a list and combines actions of selecting and mapping to where if a function returns any value except false or nil, that result is pushed on to the new array after transforming it.
So, too, you could transform and combine any function that can be implemented in reduce into grand art known as transducers, but that red is a story for another day, for you've learned much and you've had a long journey. There were merely first steps on your journey
to knowledge my apprentice, one you will soon be walking. But, again, these are lessons for another day. You've traveled far and learned much, and my time here is drawn to a close, I'm afraid. We shall talk again soon, and when that day comes, I look forward to seeing everything you've done and everything you've learned.
And with that red journey back home, where I had much to think on from this, realize how little he actually knew of reduce and all the things he had spent so much time learning already, and how much more there was to learn in the world, and that, to him, was a beautiful, beautiful thing. In all the time he had spent adventuring,
there was still so much more to learn out there, so many more beautiful things to find, friends to meet, people to greet, friends to laugh with, cry with, everything else could be. And to him, that was the most valuable part of his entire journey. Perhaps this is the end of red story, or perhaps it's just the beginning of an entirely new one altogether.
So, to wrap up, all the illustrations in this talk were actually my own work, over about 50 illustrations, 200 hours, and, okay, 140 slides, I suppose. Good, it gives me a count, can you believe that? And you will find tested examples
that will give you more information here in the repo, and I will pin this, and I will tweet this out later. And again, who I am, you can find me on various social media platforms, and I will be tweeting out various things as we go along. So, just credits, because you might have noticed,
I hid some strange things in this talk every now and then, and I did get permission, mind you. There were some very odd reactions whenever I asked for permission, but I did get permission nonetheless. So, the foxes were a homage to why the lucky stiff. Okay, good, the slides are back, we're good.
Because why was my first foray into Ruby, and he may have been in a lot of yours too. And that's just to say that whimsy, silliness, and fun are still very much appreciated in the Ruby community, otherwise I wouldn't be up here speaking, they'd probably throw me out. And then you'll notice that Mats was hiding in one of the slides as himself,
the bundler tape gun was present as itself, and DHH happened to show up as the conductor of the Ruby on Rails. Now, we have decided to have some amount of fun. You might have seen a variety of colorful lemur stickers wandering around the halls, and yes, there is actually a point. I'm not completely insane.
Not yet, my doctor has told me so. So, we have a scavenger hunt, and you might find the tag, lemurs of RubyConf being thrown around. If you search that, you will find all the people who happen to have lemur stickers here. Now, if the people with the lemur stickers would please stand up, so that people might see who you are.
Okay, take a good look around, and know that these are the people with the lemur stickers you seek. Now, people with the lemur stickers please move towards the back of the room. I hope you all are fast, because they're actually very fast as well, and I'm a very mean person.
But I will say that that is not quite all we have, because you might wonder, what is going to happen next? What is Red exactly up to, and where is he going from here? Well, you see, and if you were paying attention, you might have caught a very subtle little clue hidden in one of the slides. IGTR is not an acronym I've ever seen
on a Ruby book before, but it will be in 2019, as Red's lemur will return in a book published by No Starch Press called An Illustrated Guide to Ruby.
So, that's all the time I have here today. There's not an angry light blinking at me, so we do have some time at the end for various questions and other stuff up here on front of the stage, but I hope you all enjoyed your experience and journey into the land of innumerable. Thank you.