 This is Ryan Davis. He goes by Zen Spider on the Internet. He founded Seattle R.B., maybe you've heard of it, written rather a lot of code. He is the author of RSpec, Test Unit, Tea Package, Maxi Test, which he loves. He advised me recently, and I think it's good advice to this day, to use structs for everything. Anytime I can use a struct, I should use a struct. I don't even really have to make objects at all anymore. I just, everything is struct in all of my applications. And that was Ryan Davis' advice, ladies and gentlemen. So you can look for Zen Spider's actual work on the Internet by looking up Zen Spider. And I present to you Ryan Davis, a round of applause, if you please. So since I'm last, I don't have to start the timer, right? They're all captive, right? Please start the timer. Starting the timer. So this is my first time here. Thank you very much for having me. I think this is a great conference. I want to thank Jonan, Kobe, Josh, and everyone else that's involved. I'm sure I'm missing a lot of names. So let's please give them a round of applause. And I want to thank all of you for sticking it out to the last talk. I know you're all more than a little bit drunk, and you've stuck it out through an entire day, and now you have to put up with me. So thank you very much. As said, I am the founder of CLRB. We just celebrated our 13-year anniversary last Saturday, and we've been meeting weekly for the last nine or so years. We don't have a date of when we actually started doing that, but that's our gig, and we really love it. So as I said, I'm going to be speaking about standing on the shoulder of giants. I'm all that you finish, but my talk at RubyConf Australia was the best talk ever. And the reason why that just happened was because I did the exact same thing to all of our Lacan at RubyConf because he gave a talk called Polishing Ruby, which is the title of my blog since 2005, and some people apparently took it seriously. So it wasn't serious, it was staged. So anyways, as I usually do, setting expectations. This is sort of a history talk, and that's not really something I'm into. It has very little code. It's an ideas-slash-survey talk, and it's basically about the things that I'm really enthusiastic about that's outside of Ruby that I think we should steal. But first, a quick little story. I was a T-Totaler for about 20 years, and I stopped drinking before it was actually legal for me to start Yale College until Madison Ruby of 2012, where Whiskey, Craig, and Cheese Lady. Jeannie Carpenter gave a whiskey and cheese pairing that was sublime. And I decided, why am I not drinking? I could drink the expensive stuff, and it'll moderate me anyways, and it'll work out. So thanks for ruining my liver. And on my current diet, my liver ain't got time to filter. Alcohol currently has about a 5x multiplier for me. So I'm a little toasty. Thanks Josh for the scotch. So please bear with me when I start this slur, if I'm not already. So, getting started. About 900 years ago, don't really know when, Bernard of Blah Blah said, we, meaning the moderns at the time, are like dwarves perched on the shoulders of giants, the ancients, and thus we are able to see more and farther than the latter. But and this is not at all because of our acuteness of our sight or our stature of our body, but because we are carried aloft and elevated, that's a weird font, by the magnitude of the giants. And then this butt head showed up about 500 years later and said, if I'd seen further, it is by standing on each shoulders of giants, and that is the correct spelling for the time, deal with it. So Zach, we all stole the title. But in other words, this is not a new concept at all, Newton was just iterating on a simple idea that every idea we've ever had builds upon the ideas before them. But that really begs the question, that when we created a language, why do we build it anew more often than not? But what does this have to do with Ruby? Well, everything, otherwise this talk could have been rejected. So while it's probably unnecessary, I'm going to give a quick summary of Ruby for the second comparison later on. So here's Ruby's features, it was created by Matts in 1993, it's an interpreted file based scripting system, purely object oriented, class based runtime, incredibly complex syntax and semantics, which is why we love it, some of us. It's got an extensive, fairly extensive class library, numeric tower, et cetera, and really it's designed and optimized for developer happiness, which is really why we love it. And just as a quick, basic example of Ruby, for comparison later on, here's Fibonacci, it's a simple recursive version, Fib, optimized entirely for line count, not for readability. So here's Ruby's history, and it's actually pre-readable if not fuzzy, and as you can see, there were four years between 1819, which I consider the golden era, and five more between 19 and 20, and basically what was going on there, I don't really know, but that's what it was. But the reality is that Ruby 1.0 shipped with almost everything you used today, as far as language features go, not as far as the class library goes. Not much has been added since 1.0, we've had private and protected scoping, was added almost immediately after 1.0, class variables in 1.6, which was about, I don't know, four weeks after I started Ruby in 2000, and we had encodings version 1.0 and 1.9, which I refused to acknowledge existed, and then it was fixed in 2.0 and actually works well. And then frilly syntactic sugar was added in 1.9, 2.0, 2.1, and 2.2. Ruby is a fantastic language. I love it, don't get me wrong, but it could be better. In my opinion, it's simply just not done yet, at least I hope it isn't. And it's done a terrific job of taking ideas from languages like Smalltalk, Lisp, and to an extent, Perl. But this is what I want sometime in the future. I want more Lisp in Smalltalk, hence the thicker lines, and I want new stuff from Self and a system called Colo, which probably no one has heard of, and I wouldn't mind de-emphasizing Perl a little bit more. So here are, booze, here are our giants. We have Smalltalk by LNK, Self by David Unger, Scheme and Racket by Guy Steele, Gerald Sussman, and Mattias Filiacin, and Funk slash Colo slash a lot of acronyms, again from LNK. And many more. I by no means imply that any of these people worked alone. They all had teams and they worked with a ton of people, I'm sure, but they are the figureheads, so to speak, of those projects, and that's why I represent them primarily. So let's start, shall we? Let's do basic introductions first. First up is Smalltalk. It's one of my first languages that I actually loved, and I cut my OOT-th on it. A not-so-brief summary to compare and contrast. In this case, Smalltalk's pretty similar to Ruby as far as the runtime goes, or I should say Ruby's actually pretty similar to Smalltalk, but totally different, nearly every other aspect. It's by LNK and Dan Ingalls at Xerox Park. It was created initially in 1972, publicly released in 1980. It is bytecode-compiled, but it's an image-based system, not file. It is purely object-oriented class-based runtime, which is exactly the same as Ruby. It's incredibly simple and clean syntax and semantics. It only has six keywords, and it only has four precedence levels, which is vastly different than what Ruby does. It's got a fully immersive development environment. It is an incubator for ideas. A lot of what we do today came from Smalltalk, including a lot of object orientation patterns, the entire pattern system started from Smalltalk, MVC, et cetera. It was way ahead of its time back then, and it still is in many ways. Here is an implementation of Fibonacci and Smalltalk. I've grayed out the pseudo syntax that really exists when you export Smalltalk to files. Since Smalltalk is image-based, you don't normally see that stuff. You only do that when you export it for the sake of schlepping it somewhere else. Otherwise, it's pretty readable to us Rubyists. You have the method signature. The carrot means return in Smalltalk. So you have self less than two. If that's true, evaluate to self. If false, evaluate to self minus one Fib plus self minus two Fib. Nothing interesting there. Next up is self, which most of you have probably never heard of. Has anyone heard of self? Language files, yay. So brief summary of self. It's by David Unger and Randall Smith. It was started at Xerox Park as almost everything was back in the day, but it was finished at Sun in 1987 the next year. It's bytecode compiled, jit-based, plus a jit, image-based file system, sorry, image-based system. There is no files other than the image itself. It's not really object-oriented, but it's classless, a.k.a. prototypes, runtime. And it's incredibly simple slash clean syntax and semantics, much like Smalltalks, actually almost exactly like Smalltalks. And the thing that just blows my mind is that the VM itself only has eight bytecodes. Eight. If you compare that to Ruby, I have no idea how many Ruby's has. Yeah, I'm not paying attention. We have a lot more than that, and most languages do. The book on the JVM is an inch and a quarter thick, and it's nothing but the instructions in the description of the architecture. It is a fully immersive development environment, much like Smalltalks. I will see differences in that later. And it's also an incubator for ideas. Partotyping really came from self. Java Hotspot was born here. A lot of things were born here. And it's kind of a shame that not more people have played with it. So looking at some code. The one thing of note here is that less than or equals to in self, they really mean it when they say that self is optional. So there's an implicit self on the left-hand side of that less than or equal to. Otherwise, it's almost exactly the same as the Smalltalk code, except that they use predecessor. And the self is also implied in the minus two as well. Which is bonkers, but it's kind of neat that they want that direction. OK, my current non-Ruby love is Rackett, which is a type of scheme. And I'll be doing a quick summary of both those things so that you kind of get kind of an idea of where we're coming from. So scheme was by Gerald Sussman and Guy Steele. It was started in 1975, and the work on it went through the mid-80s, I believe. It's a minimal variant of a lexically scoped lisp, which fixes a lot of the semantic problems that we have with the older lisp and with Common Lisp today. Lisp is a functional language based on lists as the main data structure, and it's innovation galore here. These guys came up with tail call optimization, the transparent numeric tower that we have in Ruby today, hygienic macros, first class continuations, and a lot, lot more. It could be an entire talk on its own. In comparison, Rackett is a maximal scheme. It's by Mattias Filiacin and the PLT cohort. It's a maximal variant of scheme. It has a huge, incredibly diverse library with lots of, like, graphic tools and all sorts of other stuff. It's fantastic to play in. It's bytecode-compiled, has a JIT, and it is a file-based system. It is mostly functional, and it has a multi-language runtime, which is vastly different than everything else I'm talking about. It's got a very simple syntax like all lisp and semantics with rich expressions like extensive macro system and structural matching, and it ships with both an editor as well as a runtime. And here, like lisp, there's a lot more parentheses than there are in other languages. It's a prefix notation, so math operators go before the numbers involved, otherwise this really isn't that mystifying. It reads just like anything else. And finally, there's COLA, or what I refer to as a beautiful, tiny, tiny kernel. And in the theme of this talk, this comes back around to LNK, building upon the shoulders of giants. Brief summary of VPRI, Viewpoints Research Institute is LNK's think tank. They got a five-year grant from the NSF to work on what's called FUNC, which is Foundations of New Computing, and their main project is called STEPPS, which is Steps Towards Expressive Programming Systems, which doesn't mean much. They want essentially to do a whole system from soup to nuts that's understood in one brain. We haven't had that our entire lives. The entire system from language to GUI apps that actually allow you to produce real things in approximately 20,000 lines of code. No OS, no nothing else, no nothing. Just that, 20,000 lines of code. So a brief summary of COLA, it's the main sub-project, or one of the many sub-projects of VPRI, which is just one incarnation of the underlying runtime. It's an odd statement, but this is because VPRI is a rapidly moving target, and every time I think I get an understanding of what they're working on, they come out with another paper that says, no, we've moved six miles over this way. And it's kind of hard. But it's a machine-compiled file-based system, object-oriented prototype-based runtime. It's small talk-like, but lisp-like at the same time. It's incredibly simple and clean syntax and semantics. There's a pattern there that I really like that, which is a wonder why I code in Ruby. But I love both things, and it's something I have to deal with. And COLA stands for Combined Object Lambda Architecture, which I'll explain later. And it's basically, that system is a system designed to be the simplest possible language that can be described in itself. And if you look at the implementation, it is about as simple as it can get. So the implementation in Fib can be both lispy and small talky, though I think that that feature is either removed or de-emphasized in later incarnations of it. But in this version of COLA that I'm coming off of, you declare that there's a method called Fib on integer, and whether you use the curly brackets, you go lispy, and whether you use the square brackets, you go small talky. And otherwise, the code is exactly the same as the other examples we looked at. So, those are the four systems I want to go into. Now it is time to plunder. As I said before, small talk is where I cut my OOTEF. My first year of college, I was trying like mad to figure out what this object orientation stuff was about. Tried with object Pascal and a whole bunch of other systems. This is well before I really caught on, so it wasn't so prevalent as it is now, and there weren't nearly as many resources. And it wasn't until I came across a pure system that you were completely immersed in that I finally understood what OOTEF was about. So, back on the day, Alan Kay and his entire cohort left Xerox Park, because Xerox Park was notorious for coming up with really neat ideas and not knowing how to sell them. And they went to Apple to work on Squeak Small Talk, which is an open source project that you can download and play with today. Don't do it on this network. They decided they really disliked Coding and C, which is what their implementation was written in at the time. So they rewrote Squeak in Small Talk, and what they wound up doing was finding a statically compilable subset of Small Talk, writing the entire runtime in that, and writing a subset to C Translator written in Small Talk as well. And being able to use that to bootstrap another version that you can then compile and link and then fire back up and be in a new incarnation of Small Talk altogether. And what that does is it lowers the bar, increasing the contributor base, because you've now dropped it down to one language that everyone can understand and is actually much higher level than C ever is. And you get a lot more feedback and a lot more contribution from it. The speed of releases and the speed of commits went up drastically once the system got up and running. And of course, they have their bumps and everything. When they started off with the first version, I'm sure they had tons of debugging code in there, and it was slow as dirt and everything else. But you do iterations, and you increase those iterations, and you increase the speed of those iterations, and it smooths out quickly enough. Small Talk has a huge class library. Right here is a quick little list, or partially list, because there's actually, I couldn't fit it all. There are 66 collection classes. We have Array and Hash, and if you require it, we have Set. And we might have some other stuff, but call it two. They have 66, and you can basically pick and choose what sorts of optimizations you want, and what type of storage you want, and et cetera. They have 32 magnitude classes, which is the one that does fit, and there's basically anything number like at all is underneath the magnitude hierarchy. Our core and standard lib aren't even close. Our core libs, we have outside of the Erano namespace, we have 93 classes. So basically, just between their data structures and their numbers, they already out mass what we have in Ruby. But more than probably anything else, Small Talk has language-supported developer tooling that massively increases productivity, like nothing I've ever worked with since. Small Talk was one of the first GUI systems following the Xerox Star, both of them born at Xerox Park. Here we see a workspace in Faro Small Talk, which is related to Squeak Small Talk, it's a fork. And we have a workspace, which is kind of like a REPL, a class browser and a test runner all on screen. The in-memory class browser, this is your normal editing environment when you're actually writing code, it's per method. So the source code down on the bottom left is a single method worth the source code, and you use the selectors across the top to go through the categories on the left, then the classes in those categories, then the method categories on the third pane, and then finally the methods in those method categories. And it allows for a huge amount of organization and allows you to actually hone in on what you want much quicker than having to grab through a file or use tags or anything else. It has a built-in debugger with resumable after modification contexts. So one of the things that really differs in Small Talk is that failed unit tests bring up the debugger automatically. And what they do, they call debugger-driven development rather than test-driven development. They write a test that fails, the debugger comes up and in the debugger they implement the passing solution and they click resume, and it goes green. What that does is it just tightens the feedback loop absolutely and development just screams as a result. They have introspection facilities like senders and implementers browser that lets you look across all your code for a single message. And here we're looking at the to buy method and you can see that it's implemented in both date and time and number. And you might use that when you're starting to refactor and you want to see all the different ways that a method is used or you need to see all the people that are implementing something or calling it. And there's a lot more. The first refactoring browser ever made was made in Small Talk. Every time I get an argument with someone who say that you need static typing in order to have all the information you need to do code analysis and that type of thing, I just point to the refactoring browser in Small Talk and say, no. There are linting tools that go way beyond syntax checking and way beyond basic style issues. They go into this is not as fast as if you use this method. This is potentially buggy in these scopes, so on and so forth. And I ran it across their own class libraries and it started to point out problems, which was amazing. I really like that. And there are a ton of DevTools in Small Talk. I could do an entire talk about just the DevTooling in Small Talk. And I can't do that. So one of the things that I think is kind of painful and ruby is that there's all these little road bumps along the way as you code. The equivalent to our inspect message in Small Talk is actually useful. From the ground up, Small Talk has a culture, scotch, where the equivalent of the output of inspect is runnable. And so if you asked for a darker version of the light red color, you'll get that output if you, say, print this out. And that code is runnable as is, and you'll get another version of the same output or another version of the same instance. Whereas in Ruby, when you ask for the inspect of color.new with the exact same values, you get this thing with hash, angle bracket, class name, for some reason the address, which is much less useful now that we're all on 64 bit machines, and then the iVars. And because it starts with a hash, that's basically a comment. And even if you took that out, it's not runnable. It's just not useful information at all. And if we had started Ruby from the beginning, where inspect, since it's meant for developers anyways, output something that we could run, then you can do a lot more with that. So self is different. It's a very different system. It's a strange system. It's a system that I don't entirely understand. There's more focus on its runtime than the language itself. It is a direct descendant of Smalltalk. So in that sense, the language isn't much different. This was the birthplace of JIT. David Unger, his PhD was under the David Patterson, the architecture guy. And his PhD thesis was titled The Design and Evaluation of a High-Performance Smalltalk System. His later publication called Soar, Smalltalk on a Risk, is the best book on objective optimization I have ever read, Barn None. The man uses numbers for everything, and it's impressive. And as a result, they made a Smalltalk system that ran on a risk CPU, custom risk CPU, back in the mid-80s, which is just unheard of. This is the reason why JavaScript and Java are fast. He was finished self at sun. Java came from sun. Do the math. Basically, JITing using monomorphic and polymorphic inline caching means that dynamic languages really can be fast. Self is also the place where prototyping was really, if not born, then popularized. Some agent systems did show up in the mid-70s, but I don't know if they connected the dots necessarily between the two. But basically, classless OO or prototyping started itself as far as I'm concerned. This influenced JavaScript and languages like IO heavily. And prototyping is really handy. Since 1.9, and I just learned this on the airplane down, we have been able to add methods to an instance of one class from a completely different unrelated class. But you still have to write some rather ugly code to be able to do it at all. And it still doesn't really work, as you can tell in the last line. It doesn't make sense. Basically, self is wrong in the context of those methods. And self has in much the same way as small talk, but much not. A lot of developer tools, a big portion of the system is developer tools that, again, we lack. Like small talk, self has a GUI right out of the box. It is a lot more spartan than small talk's GUI, but with an emphasis on the objects themselves. And in this case, wow, that's fuzzy. Where's it my eyes? I'm kind of drunk. So in this case, you're sitting on this giant, infinite canvas, and you're actually walking through a tutorial that's telling you how to do self itself. And the next step, previous step buttons at the bottom will move you to a different part of a canvas with more of the tutorial. It's really cool. All objects are tangible GUI elements, making them easier to inspect, interact with, and manipulate. And as you can see on the left, I have an instance of a slots object with a bunch of methods or slots. And then that box at the bottom is kind of a repl for that instance. Self will evaluate to that object. So you can interact with it directly and manipulate it directly. And it's really, really handy. The standard tools let you get into and manipulate objects directly. Here we can see that we can add more slots or add a category of slots. We can copy slots or move them around, push them up or down with its parents or its children, and do a bunch of things that we actually don't do very much because we are class-based. And of course, there's a built-in debugger with a reasonable context that lets you easily experiment with the code live. One of the things you'll do is you'll write some code in the evaluation box. In this case, I'm explicitly calling halt to bring up the debugger. But you'll write something that doesn't work. It'll say the method doesn't exist or whatever. And then in the debugger, you'll implement it, make it pass, and move on. OK. So as I said before, Racket is my current non-Ruby love. I am a polylingual amorous. Racket is incredibly polished, very responsive development team, and just plain fun to code in. It really, truly is. It ships with extensive documentation, both in the reference side, where we got functions being declared here, and in a newbie-friendly guide as well, with hundreds of pages of stuff. And honestly, as much as we've put a ton of effort in improving the core library and standard library documentation, Rackets.co puts Rubies.co and RDoC to shame. The system is just night and day different. Racket ships with an IDE oriented on beginners. It was originally intended to be for teaching high schoolers. And I'm running out of time. Hado code. But it's perfectly usable for advanced devs. There's a repl integrated on the right, and you can split other direction. And it can even display generated images. As we can see with the Sipransky triangle here. The documentation is integrated, so you can quickly look up any function that you're using simply by selecting it. And when something goes wrong, you can see exactly where it is and where you came from. That kills me. Racket has a family of functions all related to the name Match, which provide better structural decomposition than what we have with Ruby's Splat Operator or the array destructuring assignment that we normally use. It's of limited use to us. It really truly is, because it only works with arrays or array-like things, meaning that they implement too airy. It doesn't work with objects. And we work with a lot more than array or array-like things, so we need to have more. And the thing that kills me about Racket is that that first line in all source files, pound lang, declares what language you're actually coding in. Racket supports a meta-language system that allows new languages to thrive, and it is absolutely perfect for our DSLs and the way that we are like to write our code. In this case, we're looking at the manual variant of their documentation language Scribble. And what this actually does is it runs this just like it's code, even though it looks like it's just pros to us or pros with some markup, and generates Lisp that winds up executing itself and will output itself to either PDF or HTML or whatever else the back end does. So object orientation is good for organization. It's good for scoping. It's good for data hiding. But at the end of the day, Lambda is king. As a quick comparison, doing the Fibonacci code as above with Fib 30, 31, and 32, you can tell that the runtime differences are night and day. And some of that speed is attributed to how Scheme runs versus how Ruby runs. That's fine. We're a much more dynamic language in that sense, but it doesn't account for this level of difference. They're 17 times faster than us, and we need to speed up our method calls by at least 4 to 8x to compete on more than the Python and Perl playing field, which we're currently competing on. And finally, tail call optimization, not to be confused with tail call recursion, which is a subset, is a seriously useful thing and can help us speed up Ruby quite a bit. We do have it optionally, but it's not on by default. And I don't know how actually usable it is because it's not on by default. It does make things like debugging harder. So when you get an error in Scheme, you're not exactly sure where you're coming from unless you're in that IDE, which will draw the arrows for you. But there are pragmatic solutions to this, so that's a technological argument that's bullshit. So getting to COLA. I have two more minutes. You stand back. I don't know if I can do this in two more minutes. This starts to get really hard for me, and maybe I bit off more than I can chew, but I love what these guys are doing so much that I just couldn't say no to this section. Steps' vision of computing is massively powerful, but it's also massively hard to explain, especially since VPRI is a rapidly moving target, and they come out with a new paper, and I'm just like, but you said you were doing x, and now you're doing y. They want to make an entire computing system up to productivity GUI apps in 20,000 lines of code. And here is, I believe, the presentation view of their system. They also have desktop publishing, and email, and web browsing, and all that stuff in 20,000 lines of code. So to put that in perspective, Debian's 283 million lines of code. OS 10 is 86 million lines of code. You know, go down to free AST, which is a much simpler system. It's nine million lines of code. Ruby's 1.2 million lines of code. It doesn't do half of what Steps does, and they're doing it in 20,000 lines of code, or 160th the amount that we're doing it in. And part of that's just because they took an entirely different approach to it. COLA, the combined Lambda object. Wow, object Lambda architecture. Yeah, Scotch. Is there combined object Lambda architecture? It's used to define their entire runtime. The concept's really simple. Use objects for storage and organization. And use lambdas for execution, for doing all the stuff. And that makes sense, right? Code needs to go somewhere, it goes in objects, and the objects need to do things. That's the lambdas. And that makes a perfect dependency loop. But bootstrapping that dependency loop is another issue entirely. So this is the simple version of the object graph. It looks something like this. This is absolutely minimal, so if any of it is implemented incorrectly, I'm gonna pause the red. Go away. If anything's wrong, the whole thing's broken, and you get to guess at it, because you can't really debug it, because it's just fucking broken. Ometta is their grammar engine. It can parse both text and object syntaxes, like ASTs. And by having many layers of translation laws, you'd have thinner, simpler layers. This, more than anything, is probably their biggest multiplier on code size. And this is several of their languages and how it translates down to the CPU. The actual languages involved are immaterial to our talk. The fact that they're translating through multiple layers through multiple languages is the key. And they don't have to translate to other pieces of source. They could translate to ASTs, and then you write a grammar for the AST to do transformations against that to output a different AST. So, another thing you do is to define your systems using basic axioms. But what the fuck does that mean? That's vague as hell, right? It means that you teach your GUI geometry and give it a rule engine and have it figured out itself. Instead of implementing every combo of everything possible, like you would if you were using GTK in their 650,000 lines of code, these guys implemented it in about 250. So, in your runtime, between using grammars and transformers, sticking to systems of axioms and a rule engine, it makes your runtime much smaller, much more understandable, much more maintainable, it lets it stick in one head. In that sense, it's something we need to seriously consider. And I know that this section was very hand-wavy. It really is. It's really hard to illustrate as compared to the other ones where I can just show some code. If you wanna unhandwave it, if that's a word, please go read the papers that they've published here. They're absolute gold. So, in conclusion, and a couple minutes late, I've surveyed a minority of ideas, blah, blah, blah. Ruby's really at its best, borrowing great ideas from other languages, but it has fallen behind. It's lost its way, and it's time for Ruby to step up and do more with these ideas and keep pushing forward to stand upon the shoulders of giants. Thank you.