 Hi everybody, my name is Jeffrey and I have a confession to make today. I love using Ruby. There's just something about it. Yeah, you can applaud for that. Okay, starting off with some applause. And you know, the funny thing about Ruby is I wouldn't be surprised if many of you in this room feel the same way. There's just something about using this programming language, right? And I'm really interested in the question of why. What is it about Ruby that makes people fall in love with it? And to some extent, this is kind of a personal question. It might just be a matter of taste. But I do think there are tools that we can use to systematically analyze this question. And the value of doing this analysis, it's not just for intellectual curiosity. I think when we as engineers want to design successful systems, it's really important that we look at other successful systems and try to learn everything we can from why they work, why we like them. And whether it's a programming language or a framework or other products, there's a lot to be learned from doing this sort of analysis. And so today we're going to try to dig into this question of what makes Ruby what it is, what can we learn from the design of this language that we all love. And the lens we're going to do this through is by comparing Ruby to other programming languages. So Matz, the creator of Ruby, is kind of a huge programming language enthusiast. He loves checking out weird other new programming languages. And he says, the reason is by learning other languages, we can broaden our horizons about what's out there and we can more deeply understand Ruby itself. So one tech we can take on this is to compare Ruby to other modern programming languages that we might use today. Like Rust, wow, bird in the auditorium. That bird loves Ruby too. So we can compare Ruby to other languages that we might use today like Rust or Python or Java. And there's some value in this. But I kind of think of this as like trying to understand a person by comparing them to their friends or their peers. That's not how you understand a person. To understand someone, you gotta meet their family. Meet their parents, understand where they came from, how they were raised. And so that's what we're going to do today. We're going to meet Ruby's family. We're going to explore three prominent programming languages that contributed heavily to the design of Ruby, Lisp, Smeltok, and Perl. And as we go through these languages, part of it will just be introducing those who haven't seen these languages before to what they are. But we're also going to dig deeper than that. And what I want to get at is not just these languages in isolation, but how are they all combined to become this one coherent language called Ruby that we use? What can we learn from the design decisions that Matt's made in combining them? And also, there's a lot of cool forgotten ideas that these languages had that didn't quite make it into Ruby or have kind of perhaps been forgotten entirely today. And so maybe there are some of these ideas that you can draw inspiration from in thinking about how we can move forward the way that we do programming. So let's get started. Starting with Lisp. Can I see a show of hands? Who here has ever used a Lisp before? Okay, so a good number of people. Those of you who didn't have your hands up, you might be wrong. So Ruby was actually originally a Lisp according to Matt's. He says maybe it could have been called Matt's Lisp. Now for those of you who've used Lisp, this might seem kind of surprising. But we'll get to what he meant by this. So what is Lisp? In 1958, this guy, John McCarthy, a computer scientist, was thinking about a problem. And the problem he was thinking about was not how to make a new programming language. The problem he was thinking about was how can we describe computation algorithms in a new way? What's a new set of axioms to describe computation? And what he came up with was this idea that eventually became the language called Lisp, list processing language. But that wasn't the core of his intention. Now Lisp was a pretty simple idea. You have these data structures of lists and a few very simple operators for manipulating lists, things like chopping them up, putting them back together. And the amazing thing about Lisp is, out of just those primitives, you can actually describe any arbitrary computation. So one of the most famous examples of this is that you can write an interpreter for the Lisp language itself using a very small number of primitives. Now to kind of appreciate the significance of this achievement in the arc of computing history, we can kind of look at languages on this spectrum that we talk about a lot, from low level to high level. So low level means close to the hardware, high level means close to the way that humans think in an abstract way, right? And until Lisp, we were kind of on this slow, arduous climb from the bottom. We were layering on top of how the machine works, slightly better ways of thinking, but we were still pretty low level. Lisp was not just another layer on top of these layers. Lisp kind of flew in from a totally different direction. McCarthy was not thinking about how can we paper over how computers work. He was thinking about describing computation in an abstract way, completely decoupled from how computers work at all. And I think sometimes people will say things like, Lisp was discovered, not invented. This is what they're talking about. This is what was different about Lisp at the time. And when you think about this in the context of Ruby, I think you see a very strong lineage from this idea to this day. The idea that we want our systems to be designed primarily around the way that people think, rather than the way that machines think. And the system will figure out how to translate what you're thinking. It kind of relates to what David talked about in his keynote yesterday. There's a lot of conceptual compression going on in Lisp and in Ruby. Now, because Lisp was essentially the first real high level language, there are many, many specific things that it introduced to the world that Ruby got. Conditionals, dynamic typing, garbage collection, symbol types, all came from Lisp at first. But there's one area that's particularly interesting to look at, I think, which is how Ruby incorporates the way that Lisp thinks about functions. So in Lisp, functions were treated very differently from prior languages. They're just values that you can create and manipulate at runtime. So here, we're using the lambda keyword in Lisp to define an anonymous function that takes an x and multiplies it by two. And Lisp also introduced the idea of higher order functions like map, which can take those functions as arguments and do stuff with them. Now, if you've ever used map in Ruby, you understand the power of this way of thinking, right? And in Ruby, you can actually kind of directly translate this code. There's a lambda keyword, there are function types. We basically have all of this directly inherited from Lisp. So some of you are kind of squinting at this, because this isn't how we normally do map in Ruby, right? We actually don't use the lambda keyword very much. We use these things called blocks. Now, we all get used to using blocks every day, but have you ever thought about the question of, what are blocks really, and why do they exist at all? Why not just use lambdas? So what are blocks? They're kind of weird. They're not objects. Everything in Ruby is an object, right? Not blocks. If you type that into an IRB, it is not a standalone thing. You have to define a method that takes a block as this invisible argument that you can't see and calls it. So what's the point of this? Well, I think that blocks are basically a very concise syntax for the special cases where you need to pass one anonymous function to another function, one and only one. But it turns out that that special case is tremendously common and actually really useful. So here, we have this kind of pipeline of functional transformation on some data in Lisp and Ruby. And the Ruby is just cleaner, because we often have this case of just passing one function into something else. Domain specific languages. On top, I have what our spec might look like if it was written in Lisp. Lots of parentheses, lots of lambda keywords everywhere. And Ruby, just having this concise syntax for one anonymous function being passed enables all sorts of stuff. And you see this used all over the place in Rails and migrations, rake tasks, and so on. Now, I would argue this is actually inconsistency. In Lisp, you have this one thing, lambdas, that you can use everywhere. In Ruby, you have blocks, procs, lambdas. I know it took me a while to wrap my head around the differences between all those different things. If you ever need to pass two anonymous functions to a function, you can't use blocks anymore, you have to switch to a totally different syntax. So it's arguably more confusing, more complex, and inconsistent. And yet, blocks add so much to the language, right? And so I think what I take away from this is that we often hold up consistency as this key goal of design, but actually sometimes a little bit of inconsistency in a system optimizing for those special cases that are really high leverage can be a great choice. Let's talk about syntax. So this is a little bit of Lisp syntax. Looks pretty different from Ruby, right? This is called S expressions. And there's this fun fact of computing history, which is that this famous Lisp syntax was actually not originally intended to be the syntax of Lisp. It was supposed to be the internal syntax that they would use in the interpreter. But someone on the research group just wrote an interpreter that used this syntax directly. That got popular, and the rest was history. And John McCarthy, the guy you saw earlier, wasn't actually a fan of this. He wanted M expressions to prevail in the end, but he has this great quote that I think anyone who's done software engineering will kind of resonate with, where he says, that project was neither finalized nor explicitly abandoned. It just kind of receded into the indefinite future. So we got this syntax. And actually, there's a lot of nice things about Lisp syntax. It mirrors the abstract representation of the code very well. So you have very little parsing in the language. You can do cool things with macros that manipulate this code as data. Anyone who uses Lisp will say, don't worry about the parentheses, you'll get used to it. But if Ruby started out as a Lisp, why didn't we get this syntax, right? Ruby got its syntax from another language called FORTRAN. And whether or not you think that Lisp syntax is better or worse, and there are tons of debates about that that I'm not gonna get into now, I think that there was really no choice when Matz was developing Ruby. Whether or not he thought that Lisp syntax was better, by 1992, there was a clear winner, right? All of our languages that we use today, for the most part, used the FORTRAN tree of syntax. And so I think there's this idea that sometimes if you wanna be a widely adopted thing, even if you think there might be something better, you just have to go with what everyone's using. And I think Ruby syntax is a great example of that. If Ruby had used Lisp syntax, I truly don't think that we would all be here today using it professionally. And so I think we might see similar things going on today with, for example, the Rails treatment of the modern JavaScript ecosystem. Maybe some people in the Rails community have the reservations about how people do modern JavaScript, but it's a trend. And to stay relevant, sometimes you just have to go along with those trends and not fight those battles. So there is kind of a fun question of, well, there's some cool stuff you can do with Lisp syntax that you can't do with Ruby, but can you do it with Ruby? So there's a gem for Ruby, a Ruby parser written in Ruby, where you can give it any Ruby code as text and it will parse it into an abstract syntax tree for you. This is just data. So you can actually do whatever you want with this tree, and then you can unparse it back into Ruby code and do whatever you want with that. Now you might be thinking, this is a terrible idea and you would be right, but there are some interesting use cases for it. So for example, there's a gem that does mutation testing, which is when you take your code and modify it randomly and make sure your tests fail. And that uses this sort of thing under the hood. So it's interesting to think about, can we do some of the things that Lisp people do with macros using these sorts of tools in Ruby as well? Now, of course, we don't need to resort to this thing very often in Ruby because we have other tools for doing metaprogramming and that brings us to our next language, Smalltalk. So can I see a show of hands? Who here has used Smalltalk before? Okay, a few hands, fewer than the Lisp hands. So Smalltalk was the first object oriented language. And as a result, it had an enormous influence on Ruby. The language was primarily created by this guy on the left, Alan Kay, with his collaborators Adele Goldberg and Dent Inglis at the really legendary Xerox PARC Lab in Palo Alto in the 1970s. Alan Kay's goal was a little bit different than John McCarthy's. He was more focused on kind of the human aspects of computing. Kay's vision was a world where anyone can write programs that they want to use, whether it's an architect, designing architecture software for themselves, or kids making games for themselves. And I think this resonates with David Tsikino from yesterday morning around making technology more accessible to more people, right? By conceptually, by creating the right abstractions and compressing a lot of the complexity under the hood, the vision is to create a system that anyone can use to make the programs they want. And this is part of why he named it Smalltalk, this focus on kids using the language. There's a funny other part to why he named it Smalltalk which is that Alan Kay says he was fed up with these systems with huge names like Zeus and Thor that didn't really do anything. And so he wanted to make a system with a cute little name that actually did a lot. Now Smalltalk wasn't just the first object oriented language, it was actually much more than that. So Smalltalk was an editing environment for that language for which they obviously had to invent the modern graphical user interface. They had to invent overlapping windows. Not only that, they needed a programming paradigm to program the user interface. So the model view controller paradigm was also invented in this lab. So it's kind of not a stretch to say that most of what we do today in some way came out of this one lab at Xerox Park. And by the way, down the hall, they were developing Ethernet and the modern personal computer. So it was a really extraordinary place. But for the purposes of this, I think focusing on the object oriented part of Smalltalk is the most interesting piece. So Ruby's an OO language, right? And we often have these conversations about the right way to do OO or OO techniques. Sometimes we even ask what is object oriented programming at all. And I don't know if there's one real answer to this question, but I think we can ask, what was the original goal of object oriented programming? What was the intention? And to that, we look to Smalltalk. So Alan Kay did share one goal with John McCarthy. He was looking for a way of describing computation in a beautiful, consistent way. And so because of that, he was a big fan of Lisp. But he had some problems with Lisp. And amazingly, as small and consistent as Lisp was, Alan Kay thought it wasn't enough. He was concerned that there were some parts of Lisp like that lambda key where we saw, which themselves could not be implemented in Lisp. They were special cases built into the language. And Alan Kay wanted an even tinier core to the language that could be used to compose computation of arbitrary complexity. He famously wanted the syntax to fit on a single index card. So he kind of went back to the drawing board and said, all right, up until this point, we've been taking our computers and we've been splitting their capabilities into different bits that are less powerful than a whole computer, things like functions and data. And Alan Kay said, what if instead, we split the computer up into millions of little units that were all individually as powerful as the whole computer itself? You can kind of imagine it as a bunch of computers connected by this really fast network. He said in computer terms, Smalltalk is a recursion on the notion of a computer itself. So this is the core idea that started object-oriented programming. This is where it all came from. And if you think of it in these terms, it's really interesting how so many of the other ideas that we get in OO flow from this way of thinking about it. So what does this mean in practice? When we do something like three plus four, in Smalltalk that is not just three plus four. You are taking a computer named three with all the capabilities of a computer and you're sending it this message plus and you're another computer called four. And what that thing does with your message is entirely up to it. You have no control over it. So one way I like to think of it is it's almost like you're sending a remote API request to this web service called three. You're saying, can you please plus four? You have no control over what it does with that, right? And this idea of giving the receiver of a message so much control over what it does leads to really interesting possibilities around highly dynamic behavior. And that's kind of the gist of what OO started as. It's really remarkable as I started researching this talk how many of the constructs in Ruby that we use for OO are literally just direct translation of how you do it in Smalltalk. So in Smalltalk, you can send a message to three saying add four. In Smalltalk, you can ask three, hey, what kind of thing are you? Are you an integer? And it will tell you. In Smalltalk, classes are also objects. So you can ask the integer class, what kind of thing are you? It's just a class. Even the idea of control flow iterating over arrays using message sending and blocks comes right out of Smalltalk. The way that we do metaprogramming in Ruby largely descends from Smalltalk. So in this Smalltalk snippet, what we're doing is opening up the integer class and we're saying when you don't understand the message that gets sent to you, do something. In Ruby, we can do the exact same thing. We can open up integer and define method missing. This idea descends directly from the core principle of a receiver of a message having full control of what it does. It doesn't have to look it up in a preexisting table. It can really do anything. Now there are other things that we didn't get from Smalltalk that kind of didn't make the cut. And I think those are interesting to look at as well. So one example is conditionals. In Smalltalk, there are no conditionals because that would be another special case. We want to keep things consistent and recursive for member. So in Smalltalk, conditionals, you just take a Boolean object and you send it two messages, if true and if false, with blocks of code for each case. And you can do this in Ruby. People have done this. There are gems you can use for this, but we don't do it that way. And it's interesting to ask why did Matz abandon the Smalltalk way of doing conditionals? And I don't know the answer. You know, I don't know why he did it exactly, but I would point again to this idea of introducing inconsistency in thoughtful ways. You know, the way that we do conditionals, it's much more conventional. Every language does it that way, right? It's arguably, I would say, easier to read than the Smalltalk way, maybe. And in the original Smalltalk system, consistency was the one overarching goal. We want this tiny language. And I think again and again, you see in Ruby, we take many of these principles of consistency, but we sprinkle in little bits of inconsistency where it helps to make things easier to use. There's nothing we didn't get from Smalltalk, which is the editing environment itself. So Smalltalk had an editing environment that was probably unique in the history of computing, and I don't think has really been replicated again. So this is a modern Smalltalk UI. You can still download this today. And in Smalltalk, your code is not organized into files the way that we typically do things. Instead, you can kind of see these modules in the left, and then you can pick a class in this menu here. Within a class, you can see categories of methods grouped by related behavior, essentially. And then you can click into one of those, and finally, you can click into one of the methods if you want and edit it. So already a different way of thinking about organizing our code, but it's not only that. It's actually, the remarkable thing is that this code we're seeing is also running underneath the IDE itself. So if I do this stupid thing I'm doing here, and I change the point accessor x to return the value of the y attribute on the point and save that change, boom. My editor itself actually blows up. Now, I know that's not the greatest demo of why is this useful, but there are actually interesting things you can get from this. So one of my favorite examples is sometimes you know the input and the output you want, and you know that there's that method somewhere in the standard library, but you forget what it's called, right? Since small talk, because the editor is so integrated with the system itself, you can just say, oh man, this video isn't gonna show, is it? So the video's a bit cropped, but what I did is I gave it two and two and four. So I said, I want two and two and four. What's the method I can apply to two and two that makes it four? And it gives me some of the answers. You can't see this cropped, but another thing that I'm doing here is I'm typing in a full date, and I'm then saying, give me the day of the week of that date. I'm just specifying the input and output I want, and it goes and finds the method for me. So really interesting behavior enabled by the editing environment being so tightly integrated with the language itself, but we didn't get it. And I think again, Matt's picked his battles, and I think he picked them well. This is a pretty radical idea. There's a lot of barriers to adopting this sort of thing, and I think if Ruby had taken all of this stuff from small talk, it's very likely that we wouldn't have the wide adoption we have today. I think using a traditional editing environment was a necessary concession, most likely to gain adoption. It is really interesting to me to think about, could we bring some of this rich editing stuff back? Ruby at its core has a lot of functionality from small talk that you need to do this sort of thing. What would it look like to start building IDEs that are 10 times more powerful than RubyMind or the other common IDEs that we use today? Perhaps something for you all to think about. Time for the last language, Pearl. The Swiss army chainsaw of programming languages. So Pearl, as you can tell from this photo, is gonna be a bit of a different situation than these other languages we've looked at. So Pearl was developed in the late 80s by this guy, Larry Wall, who was a linguist working as a sysadmin at NASA at the time. And Larry Wall was not trying to create a new set of axioms for computation. He was not trying to spread computing to the whole world. Larry Wall was just trying to get some sysadmin stuff done. And his idea for doing that was, what if we could combine some of the convenience of text processing tools like said with the power of real programming languages like C? What if you melded them together? And the result was Pearl. Now there's a few kind of slogans of Pearl that I think illustrate the thought process that went into designing this language. A program is correct if it gets the job done before you get fired. So this is not a guy trying to design a perfect new programming language. There's an extreme focus on pragmatism, on productivity, on just getting things done and getting out of your way. There's more than one way to do it. So you heard Mark mention this in his keynote yesterday evening. This slogan that we often talk about in the Ruby community came from Pearl. And you can contrast this with other languages like Python or a lot of more academic communities that wanna focus on having the one right way. It's actually really interesting the origins of where this slogan came from. You remember Larry Wall was a linguist, right? And he thought of computation as being more similar to human language than to kind of mathematical modeling. So in human language, you can express yourself in a variety of ways that are equally valid, right? And he kind of brought that ethos to Pearl. And I think we still see it very, you know, prominently in Ruby today. And finally, another slogan that he had was easy things should be easy and hard things should be possible. And this ties very directly to that principle we've been talking about of thoughtful inconsistency. Introducing those special cases when it counts to make things easier, even if it results in there being multiple ways of doing things and perhaps a slightly less consistent model. So when you buy a car, it's really important that it has a chassis that works, a transmission that works, it has wheels, right? But the interior also matters too. Having nice seats, having, you know, the detailing on the dashboard, that stuff contributes a lot to your experience of driving a car. I think a lot of the time academic programming languages focus on the chassis too much and don't really think about the interior, the detailing. And that shows when you try to use them. And on the other hand, Ruby has this very tight focus on getting these details right. It feels polished, right? A lot of the time when you're using Ruby, you notice little things that make it just nice and easy to use. And I think a lot of that stuff came right out of Pearl. Both the focus on that being important as well as a lot of the specifics. So one great example is string interpolation. Pearl has, I think, the easiest string interpolation I've ever seen in any language because every variable starts with a special symbol so there's literally no syntax, you just pop variables into your strings. Now, Ruby, we don't have it quite this easy, but we still have a pretty nice string interpolation syntax. And it amazes me to this day when I'm using other languages how often there is no good way to do string interpolation, this thing that we do all the time when we're making applications, right? JavaScript until very recently had no good way of doing this. And I think this is a great example of if you're Larry Wall and you're doing syshabmin stuff, you know string interpolation is important for getting stuff done and you're gonna make a good way of doing it. It's not a core fundamental piece of the language but it's a really important detail. And I think there's a lot of things like this. So these are all things that Ruby got from Pearl. A native syntax for regular expressions. The percent w syntax for easily specifying arrays of words. Here docs for just putting in long bits of text. I've never tried doing that in JavaScript. Inserting underscores in your long numbers to make them more readable. So again, all of these are small things, right? They don't, each of them on their own isn't a make or break feature for a language but they add up. And I think Ruby did a really good job of stealing a lot of the good stuff that Pearl came up with in this category. Now there's other things that might be a little more controversial. So global variables. A lot of languages don't even have global variables these days. Ruby does and the dollar sign at the front makes it look awfully pearly. And you know, we can argue about whether using globals is a good idea or a bad idea in production code and so on. But sometimes when you're just hacking together a script to get something to work, it's nice to use a global variable, right? And I think that's a lot of ethos of Pearl that we see still remaining in Ruby. Even these weird cryptic variables. So Ruby has these globals that have these unreadable names. This one tells you the process idea of the current running process and there's many more. These seem closer to the side of objectively bad ideas. Like you should never use these in a program. And yet, again, if you're just hacking together a little script, they can be sometimes pretty useful. It's very pragmatic. Now sometimes Pearl goes too far on this. In Pearl, if you print the string eight and you add the string one to it, anyone know what you get? You get nine. That's not good. Another example, if you take an array variable and you declare a scalar variable and assign the array directly to that scalar, what do you get? It converts it to the length of the array for you. So Pearl tells very heavily towards these kind of implicit type coercions, which remind me of some of the most frustrating parts of using a system like JavaScript. But we don't get those parts in Ruby, right? Ruby has a more strongly typed type system underneath it. And so I think when you look at what Ruby got from Pearl, it got a lot of these details and the nice bits around the edges without necessarily getting too much of this inconsistent core. So that brings us back to this question. Why do I love Ruby? Why do we all love Ruby? And I think to me summing up all of this stuff that we've seen, the answer is balance. This balance of consistency of computational model with some inconsistencies when it makes the system easier to use. The balance of the academic rigor of systems like small talk and Lisp with the freewheeling pragmatism of Pearl. You know, also Ruby's very opinionated in some ways. It is uncompromising about being object oriented, for example. And at the same time, we saw that Matz picked his battles. A lot of the more radical ideas that would have made Ruby harder to choose were left behind in the interest of adoption. And I think this balance stuff is what makes Ruby hard to pin down. You know, a lot of the times we people try to design their systems to be the most something, right? Marketing wants it to have number one, whatever. You see this all the time. You see cell networks advertising most coverage, fastest coverage, even a company like Apple that has a strong sense of design. You see them advertising, thinnest laptop, right? But I see Ruby as a good reminder that sometimes you don't need to be the most anything. Ruby's not the most functional or the most oh-oh. It's not the fastest or the highest level. It's not the most radical or the most pragmatic. It's just kind of this beautiful blend of all those different things mixed together in a very thoughtful way. And to me, that's kind of what I take away from looking at the history of Ruby. And I hope that when you go off and design the systems that you work on, whether they're programming languages or web frameworks or just a product, that you think about how to take inspiration from other good ideas and blend them together in a perfect balance to make it work beautifully. Thanks.