 So I think we'll go ahead and start. First, thank you so much for coming. I really appreciate your choosing to spend your time here with me, coming to see my talk. There's a bunch of fantastic talks that are going on. So thanks so much for choosing this one. And thanks also to RubyConf, to our sponsors, to the venue, to New Orleans. Thanks to everyone who helped make another RubyConf possible. As always, I'm super delighted to be here and I'm delighted to have you here. I apologize that I can't really see any of you. It is unbelievably bright up here. But, you know, well, you'll see in a minute why I do need to see at least some of you. So this talk is called, What If Ruby 3? But it's also known as, The Future of Ruby. Part 3, The Future. So this is designed after one of Justin's slides. So this is the third part of a three-part talk track sequence on The Future of Ruby. So we've sort of seen the past, we've seen some of the present and apocalyptic visions. And now we're gonna talk a little bit about what Ruby could have been like or what it still might be like. And we're gonna do things a little bit differently than the way I normally do talks. I normally rely very heavily on presenter notes. I oftentimes will inadvertently read rather than talk to all of you. So on Justin Searles' advice, I'm forgoing presenter notes entirely and we'll see how that goes. Yeah! Yay! Also, that's actually excellent. If at any point I just start trailing off or lose my space, just start applauding. That would be really helpful for me. It'll give me a minute to reorient. But I'm delighted not to just be friends with Justin. I'm also a client. And what that means is Justin has to buy me fancy dinners now. So... Ha ha ha ha ha ha ha! Anyway, so this is a computer talk, it turns out. And that means you have to start with zero. So hello, my name is Eric. I tend to speak very quickly, particularly when excited and I find talking about Ruby and the future possibilities that Ruby and the community have to be really exciting. So if at any point I start to go off the rails, not intended, and speak way too fast, and this is why I kind of need to see some of you, especially those of you closer to me in the front, just kind of like, or maybe something to give me a sense of ease it back a bit. And I will slow down. I'm gonna talk for between 35 and 40 minutes. If we come closer to 35, we'll have a couple of minutes for questions. If we come closer to 40, then I won't have time for questions, but please feel free to stop me after and ask me any questions or we can chat about anything that you would like. So like I said, my name is Eric Weinstein. I am a director of engineering at Fox Networks Group in Los Angeles. We're currently building a platform and a team around the content APIs, around our television content, which includes The Simpsons, Archer, National Geographic, which a lot of people don't know, Fox Sports and more. So we are hiring. Please feel free to ask me about that as well. All of my information is in this human hash I felt compelled to make. I write a lot of JavaScript and Node at work, but I write Ruby in my, well, not as much free time as I would like to have. I've been writing Ruby for several years now, and I recently wrote this book, Ruby Wizardry. I've been saying recently, I guess it's not so recent now. It's about three years ago, which means we're due for an update. But it's hard to see at the bottom, but there's a 30% off promo code, rubyconf30. If you go to nostarch.com, that's the publisher's website, and you enter that promo code, you would get 30% off the book. So if you're interested, please go ahead and do that. And thanks so much to the folks at nostarch for setting that up. The book teaches Ruby to eight to 12 year olds, but if you have questions about that, please do come find me after the show. This is not a long talk, but I do think we benefit from having a roadmap. So I'm gonna start by talking a little bit about Marvel's What If comics, then the power of narrative and meta narrative, and we'll finally look at some of the possible futures of Ruby through three What If stories. What if Ruby had a static type system? What if Ruby ran in the browser? And what if Ruby did not have a global VM block? So like I said, I'm gonna do my best not to read to you. Small classes, small methods, small slides. And hopefully the meta narrative component, which you'll see in a minute, is entertaining and not like Clint Eastwood yelling at an empty chair. So what if, so if you're not familiar, the What If comic line from Marvel, they did two separate runs, are basically non-canonical stories about the Marvel universe. What if the X-Men had been founded by Professor X and Magneto together? What if Jessica Jones had joined the Avengers? What if the Avengers defeated everybody? Which I feel like is maybe not the most interesting question, but I would read that. I would definitely read that comic book. So actually I probably did. So basically, what if things were different than they are now subject to the rules of the universe? Like what if the history and the potential futures were different? And what if is a powerful question that is deserving of powerful music? And I had wanted to use Marvel's fanfare, the, no, no, no, no, no, no, no. Like the really, someone's mutant powers are activating or they've put on their costume for the first time. But then I remembered that this talk will be on YouTube and I did not want Marvel to yell at me. So I've picked a different music. I'm actually gonna play that one more time just because I like it so much. Does anyone happen to know off the top of their head what that is? And again, apologies for not being able to see you. I can't tell hands are raised so just feel free to shout if you know. If you don't, it is actually the Bloopsophone theme song. So if you're not familiar with Bloopsophone, it was a project by Why the Lucky Stiff. You know, there's been a lot of good content today about the history of Ruby and our community. Why was a very big part of that? His projects were a very big part of it so I'm delighted to be able to share a little bit of his content and if you have questions about why, I'd never met him but I've studied him. Or if you have questions about how things used to be or Bloopsophone or whatever, please do come find me or another grumpy old person. So Ruby three by three. So Matt said this morning, the goal for Ruby three is to be three times faster than Ruby two. And I do think that we will get there but there's also a question of what else we'll get. We saw there are gonna be some new features in Ruby two five. Every Christmas we get a new version of Ruby. It's exciting to think about what could ship in Ruby three. And so as I said, we have these three what if scenarios focused around types, around Ruby's execution environment and around its concurrency model that I think could be really interesting. And it's possible that people will look back on this talk and say this was truly the beginning of Ruby three. Good, I'm glad this part works. Feel free to read that and run Howard's voice if it helps you. It helps me. And thank you for laughing. Also if it helps, if this seems a little bit new and weird and strange because this is gonna be Ruby that doesn't quite look like Ruby, feel free to think of it as a different programming language. I don't know how many of you know this but back in the day when Matz was selecting the name for Ruby, he'd narrowed it down to two and the other was Coral. So if you want to pretend you're at Coralcon for the next 33 minutes, if that helps please do. So let's start by talking about Ruby's type system and what if Ruby had a static one? So static and dynamic type systems differ in the fact that a static type system, in a static type system, all the variable types are known at compile time. So whether you have a fixed num or a string or a symbol, when you compile it you know you're not going to have something not responding to a particular message or method at runtime because you know what type it is and you know what methods it responds to and what messages it will accept. This may or may not make use of type inference so if you've written a lot of Java you'll see you're constantly indicating what type everything is. If you've written Go then you're aware that you have a powerful type system that doesn't require you to specify the type. Sometimes the compiler won't quite know what you mean and you'll tell the compiler when I'm doing this, here's the type that I mean, but generally speaking it's smart enough to figure out what you want. This is in contrast to dynamic type systems where the variable types are not known until runtime. So you can have something blow up because you've tried to call each on it and it's not enumerable or you've tried to add two things together that don't respond to the plus operator, things like that. And further, there's this notion of weak versus strong typing. This one is much more contentious than static and dynamic typing so please don't add me to tell me that I've aired totally in my distinction. So the idea here is that for the purposes of this talk weak typing does not secretly do the wrong thing instead of throwing an error, JavaScript, and strong typing throws an error rather than secretly doing the wrong thing. So according to these definitions Ruby would be strongly and dynamically typed. And to understand what we sort of mean when we think about Ruby types, I'm just gonna do a quick crash course through YARV yet another Ruby VM which is the VM that modern Ruby uses. And the steps, broadly speaking, are tokenizing and lexing, picking apart your string of code to figure out what pieces are in it, parsing it to figure out the grammar and what should happen, compilation to bytecode so we convert from human language to machine language for some definition of machine language and then we execute. You type 10 times do a thing and we do that thing. I apologize, this is a tiny bit hard to read, but at the top you have 10 dot times do n, we puts n and we end. So we'll just print out the numbers one through 10. And here, you can see below, this is the result of calling the, I wanna say it's the lexing, lexer method. So Ripper is a tool that ships with Ruby, you can use it to pull your Ruby code apart and sort of see how it's built and what it does under the hood. And so here you've got not just tokenization where you can see all the way on the right, you know you've got 10 and then dot and then times, but you also have this metadata associated, it's that middle column on int, on period, on ident. And so this is what Ruby has, this is what YAR has seen when you've typed 10 times do n puts n. The parser in Ruby, as far as I know, uses the LALR or I think look ahead, left reversed, right most, derivation parser, which effectively says go from left to right, look a little bit ahead if you need to disambiguate what rules you're going to apply from I think it's the parse.y file. You can actually see what the parser is doing if you pass the y flag to the Ruby interpreter. So if you do Ruby-y, example.rb or whatever your file is, you'll get a lot of output indicating what the parser is doing. And both of these examples come from Pat Shaughnessy's book, Ruby Under a Microscope, which if you have not read it, I cannot recommend highly enough. Is this speed? Okay, great. And then if you want to look at the YAR bytecode, you can call RubyM colon colon instruction sequence.compile, pass in your string of code, and then call disassemble on that. And again, apologies if this is a bit hard to read, but you get your bytecode instructions. Now the interesting thing here is there is really not a lot of type information. Ruby is not statically typed as we were going to Ruby bytecode. There's really nothing that will prevent you from calling a method on something that doesn't respond to that method at runtime. There's nothing about YAR that will say, hey, time out, you're trying to call plus on something that doesn't respond to it, you're trying to call this method, and that's a bad idea. Things will just blow up at runtime. Now there are ways to fix this. I don't know if any of you are familiar with this logo. I think by itself it's a little bit enigmatic. This is absolutely not something that you should do. You can do the second one if you want. I actually don't know if you can brew install Ruby. But so Crystal is the language that has that logo. And Crystal is very, very similar to Ruby syntactically, but it is statically typed. And I think it's fast as C, slick as Ruby, is the tagline for the Crystal language. So if you're interested, I think it's crystallang.org, but if you just search Crystal language, you'll find it. And this code actually works both in Ruby and in Crystal. So the Crystal compiler and the YARV virtual machine will both understand what you want and will create accounts for you. The interesting thing here is that Crystal does leverage that type inference that I talked about. So you occasionally have to tell Crystal, like I mean this, when I tell you this variable is used in this context, it has this particular type, but oftentimes you can omit the type annotations. And one of the things that I think is really interesting is that you can have something that is statically typed that looks just like Ruby. So we could, if we wanted, create a Ruby compiler and have statically typed Ruby. We would give up some metaprogramming magic. We would give up some of our rapid prototyping loop. We would be sort of sacrificing programmer speed for execution speed. And whether or not that's antithetical to the core tenets of Ruby, I think is something that is up for debate. Certainly I think there's a role for more complex type behavior. And so what I'm thinking of here is a language called Idris that I have contributed a little bit to. Idris is a dependently typed language written in Haskell, based on Haskell. And what I think is really cool about its type system is, so I've just made up this getTransactions method or function, just gives you a list of NATs. And that might not be a type you've seen before. And that is just a natural number. You know, it's a non-negative integer. I don't know why I said getTransactions and picked these numbers. It just came to me. But the interesting thing is that you have this list of natural numbers. And so if you call getTransactions with these numbers, everything is fine and Idris does not yell at you. If you use these numbers, starting with the negative four, Idris does yell at you and says, I was checking the right-hand side of getTransactions and I was told that this would be a list of natural numbers. But I don't have an implementation for negative natural number. So the interesting thing about dependent types is a dependent type also has an understanding of the values. So it's not just list of A, but you can have list of A in this range of values. List of integer greater than zero. List of string with length three or more. You can't count the number of times you've written tests for the password part of your website where you're like, oh, the password has to be at least eight characters. You can actually encode this in Idris's type system and say this has to be a string and it has to be at least this many characters long and if it's not, your code does not compile. So catching that at compilation time rather than at runtime, which I think is extremely interesting. So interesting in fact that I wrote some not very good Ruby code to emulate it. So I can share the gist after this talk. The part I kind of want to call your attention to, this is identical to the account code from before, except I've added this type method that says, look up this method, it should return a natural number and if it does not, throw an error. Deposit should take a natural number and give you a natural number. Withdrawal should do the same thing. I don't know why you would pick natural numbers because you probably want to be able to overdrive or you don't want to overdrive, but you would like to have that opportunity or you might want to, I don't know, have decimals or something, but if you pretend that your account always has seven or 10 or 15 or however many integer dollars, natural number dollars, this will catch it for you. So again, this is not any modification to the Ruby language, so there's no compilation step. This is really just enforcing pre and post conditions to say, hey, time out. You told me that this would be a natural number and you gave me a negative number or float or string, et cetera. If we did want to modify Ruby's core language, we can change the way we do type annotations and we could say, hey, you know, this is an amount and it's of type natural number or we can kind of go more Java, E route and say natural number is the type and the argument is amount. Or we can say it's a float or we can kind of take a page from Crystal's book and say, you know what, the interpreter, the compiler is smart enough to figure out what this is. Let's just use type inference and really only disambiguate when we need to. So the question here then is, is this a good idea or a bad idea? I happen to think that having stronger static types is a good idea. I catch a lot of errors at compilation time and the number of times something has blown up at runtime because something was new or I was not thinking about the shape of the data or the correct type. I do think that there's room to make these kinds of improvements. So Matt's talked this morning about good changes and bad changes and I guess the question here is really about trade offs. If we keep dynamic typing, we trade execution speed for programmer speed, potentially developer happiness. We lose some flexibility and we lose some metaprogramming magics if we get rid of dynamic typing. We keep those with the Ruby that we have now. Static typing means that our programs will run faster but we give up some flexibility for the safety of compile time checks and knowing that something is going to be a particular type at runtime no matter what. And with dependent typing, the kind that we saw with Idris and with my example of the account, we trade flexibility for sort of these ultra powerful compile time checks which may be unnecessary, may mean we write a few fewer tests. Again, it's a trade off and I think that the answer is going to be somewhere in here. So that's what if Ruby had a static type system. I suspect something like gradual typing could sort of ease its way in a future version of the Ruby language. So now we'll kind of pivot and say, okay, well, types aside, what if Ruby ran in a different environment? What if Ruby were to run in the browser? That's good enough. For those of you who don't remember, this is Netscape Navigator and this is what the internet used to look like and in some places still does. Such as on the about me pages of computer science professors everywhere. But this would be cool, right? Like this would be amazing. We could pop open the console and not have to do a bunch of hacky editing in preview and get, so for those of you who are not familiar with the magic of percent W, we get an array of strings, the strings one, two, three. We call map and we say, I actually want all those to be integers and integers come back out. For those of you who have written JavaScript, this is more along the lines of what happens. We try the first one and it doesn't work and actually I did not understand why this doesn't work for a long time. It turns out in JavaScript, if you call a method on an array and it's supposed to have two arguments but you only pass one, it will use the index as the second one. So what it's saying is I have one. I'm gonna parse int that with a radix of zero. That's basically like not passing radix. So we get 10, which gives you one, which is the right answer. The second one is two, but we're using base one, which is not a valid base. So we get not a number, which is a numeric value. That is not a number. And then for three, we get the same thing, but two, three is not a valid value for a base two system. So we get not a number again. So basically the way to fix this is to pass an anonymous function and say I actually want you to parse this number and use 10 as your radix. Now you probably could get away with writing your own parse int that kind of partially applies parse int and just automatically says, if there's no radix, it's 10, but that's a lot of work. It would be really nice if we could write Ruby in the browser. And the question is, why isn't that a thing? Why doesn't that exist? And technically it does, sort of. So for those of you who have not seen this logo before, this is Opal. Opal is a source to source compiler for JavaScript. So it converts Ruby to JavaScript and then executes the JavaScript in the browser. And we can imagine a world where we have tools like this, but we don't actually have to go through the pain of JavaScript. We can actually just write Ruby and run it in Chrome, Safari, Firefox, whatever browser you like. But I think the question we should think about is, if we had Ruby in the browser, would we all be a lot happier or would we complain about Ruby the way we sometimes complain about JavaScript? Would we, you know, what is this language? Why is it dynamically typed? Like, how come this happens and how come this, really, is it the environment or is it the language? How different would Ruby be from the beginning? It were designed to run in the browser and deal with HTML and be sort of this asynchronous first language. How different would their concurrency primitives be and how different would parallelism be in Ruby if you had to live in the browser? If you're curious about what that would look like, we can chat later on. There's another talk that I think is very interesting and this one is sort of the, it's similar to this talk in the sense that there are a lot of imagined futures and some true history. And this is a fantastic talk if you haven't seen it. This is also Gary Bernhardt. It's called The Birth and Death of JavaScript. You can find it on destroyall software. I recommend all of you watch it. And the idea here is to kind of trace the history of JavaScript and then go into this sort of fictional future where everybody writes JavaScript and nobody writes JavaScript. And one of the ways that you can accomplish that, and this is through a project that I think is maybe two years old now, it's called WebAssembly. So the idea is you have an assembly-like language in the browser that other languages can target. So JavaScript can target WebAssembly or Ruby could target WebAssembly or Haskell or Idris or whatever language you would like. And this raises the possibility that in the future, Ruby could come in a form that not only will allow you to compile to YARV bytecode, but you can actually compile to WebAssembly. And if there are multiple backends for the Ruby virtual machine or a different virtual machine that Ruby can leverage to create browser-compatible code, then we could have Ruby in the browser. And we could have our Ruby methods and classes and we can share code between the client and the server the way we're supposed to now with JavaScript, but somehow don't. And we can have all the problems of JavaScript and Ruby and everything will be great. So again, is this a good idea or a bad idea? In terms of the server side, we sort of keep control over the environment if we stay where we are, but we still have to write JavaScript. If we allow Ruby into the browser by compiling to JavaScript, this seems almost to be like the worst of both worlds, where we get the Wild West of the browser and potentially a lot of headaches of JavaScript in its environment, and we still have to read JavaScript because something will go wrong with the compilation, the source-to-source compilation. We will have to understand what JavaScript Ruby generated through Opal or whatever project, and we're still gonna have to look at JavaScript. Or potentially, we could use WebAssembly and we sort of mitigate the JavaScript part. We still have the Wild West of the browser and we may have to learn WebAssembly, but we no longer have that source-to-source headache. The sort of thing that I don't know if this happens to you, but this is actually apropos. Whenever I write CoffeeScript, I write maybe two lines of CoffeeScript and then something blows up. I'm like, oh, nope, not Ruby. And then I change it and I'm like, oh, nope, not JavaScript, back to Ruby. Nope, and then I end up just going to Coffee2.js or JS to Coffee or whatever the URL is. Just pasting CoffeeScript in to see what JavaScript is coming out. And then reverse engineer it with the JavaScript that I want until I have the CoffeeScript that I'm supposed to have. And I would like to avoid that. So again, there are trade-offs involved and certainly we don't necessarily wanna go down that route, but I do think that the WebAssembly project, Wazm as it's sometimes called, has a lot of promise and could potentially be another environment for Ruby to target in the near future. So that was our second scenario of three and our last one is what if Ruby had no global interpreter lock? And I call this part like what if Ruby had no GIL, but it's really, what if Ruby's concurrency story were different? What if the rules of Ruby's concurrency and parallelism primitives were not the way that they are today in terms of threads and new dexes and locks and things like that? So I know it's not a GIL anymore. It's not a global interpreter lock since we moved away from Matz as Ruby interpreter to YARV. It's now a global VM lock. Again, there's no need to add me about these things, but please add me if you have questions or if you wanna talk more about all the cool stuff that's in this talk. I make this joke. I don't think this has ever happened to me at a Ruby conference. I think it's other conferences where someone at the very end gets the microphone and then asks a question that is actually a demonstration of how smart they are. But again, Matz is nice and so we are nice and like I said, I have not seen that. It's another reason I'm delighted to be part of the Ruby community. So what is the GVL? The GVL is a global VM lock. Again, formerly a global interpreter lock. It's a mutual exclusion lock that the currently executing thread has. It's like the talking stick. When you have the talking stick, nobody else is talking. When you have the VM lock, no other thread can execute. This is for a couple of reasons. There are some classes in Ruby like array and hash that are not actually thread safe. There's the potential for race conditions and data corruption to occur and anything that calls out into C-Land. If you've ever installed Nokogiri then you know this is the thing that happens and Ruby sometimes compiling native extensions and things like that. It's even scarier than the browser in terms of the Wild West. So you wanna be very careful that you're not corrupting data, that you don't have race conditions and the GVL is meant to mitigate that. And not all Ruby's have the GVL. C-Ruby does, J-Ruby does not. I actually don't, I don't think Ruby needs does. C-Ruby might be the only one that has the global lock. But there are other scripting languages like Python that do have a GIL or a GVL in order to protect you from the terrifying world of C. No, nobody wants to, okay. So that one I should be nice. Just channel maths and be nice. But concurrency is a historically difficult problem in Ruby and concurrency and parallelism and I apologize if I'm sort of beating a dead horse are different and I think the takeaway is concurrency is do one thing at a time but you constantly switch among those things so you kind of make progress on all of them. So you're kind of round robbing. You know, you do one thing, you context switch, you do another thing, you context switch. And it happens so quickly that to us it appears to be happening in parallel but it's really in sequence. And parallelism is truly doing multiple things at once. You have multiple cores or multiple machines and you have a problem that can actually be split apart, solved in parallel with those pieces and not talking to each other or potentially talking to each other in terrifying ways. And then you have a result at the end, right? And as I mentioned, thread safety is an issue here. The GVL's job is to avoid race conditions and data corruption, it's meant to protect you, especially for things like arrays and hashes that are not necessarily thread safe. And it's important to also note that we could just pull the GVL out of Ruby and accept this lack of safety and really this discussion of concurrency primitives is sort of separate from the GVL. You can have the GVL and have different concurrency primitives, you can get rid of the GVL and keep threads. It's sort of, they're sort of separate questions but they're really, I think, intimately tied together. I think the shared concern here, the culprit is shared mutable state. That's what these concurrency primitives we're gonna talk about, that's what the GVL are meant to mitigate is you have some state, it is mutable and you're passing it around. And generally if you talk to people from other backgrounds or who have strong functional backgrounds, you can either have mutable state and it's local, or you can share state and it's immutable but it's when you try to change stuff and pass it around that things become really difficult. So how are we potentially gonna solve this problem in Ruby 3? This I stole from Olivier Lacarne who I think also got it from, I think it was Koichi's talk a couple of years ago. And this is the notion of guilds. And I would refer you to Olivier's blog post on this topic or if you just search Ruby guilds, you'll get a whole bunch of resources. But the idea here is to have sort of a concurrency primitive where you separate out what can be done safely done in parallel safely done concurrently and what can't. And so if you have threads that are running in the same guild, they are not able to run in parallel but threads from different guilds can. And so the idea here is sort of tackling that problem of shared mutable state by limiting how mutable state can be shared. And I apologize if it's a little bit tough to read on the dark background. But basically the idea here is that you create a new guild and you have that guild running separately so that when you call Fibonacci, you can rely on the guild to sort of manage parallel execution for you. This is not necessarily separate from the GVL, it's not necessarily going to save us from it. In fact, if I recall correctly, you do have a GGL which is a different lock for the guild. And so really what we want is something that gets us away from locks where we say we don't actually want to restrict access to something, we just want to be able to safely do things at the same time. Turns out Matz has a thought on this and this is a little unfair because this tweet is from three years ago. But I found this very, very interesting. He says, my vague plan is add more abstract concurrency such as actors, add a warning when you're directly using threads and then eventually take the gil away. If you're not familiar with the actor model, the idea is that actors are kind of this primitive thing in your universe and they can make local decisions. They can create a finite number of additional actors, they can send messages around, but basically you have actors that communicate through message passing and they can determine how to respond to messages and things of that nature. They can modify their private state but they can only communicate through message passing. And if you've used celluloid, I think celluloid is a Ruby gem that's a very good example of the actor model used in the Ruby universe and this alleviates a lot of problems that we have with locks because we no longer need them if we say you can modify your own private state but if you want to change something else you have to send a message and so we no longer have to lock or restrict access because we've already fundamentally said you can't change anything that doesn't belong to you. And if you've come from a Rust background or you've started working with Rust, then there's also this notion of borrowing and the borrow checker. And again, you have this notion of ownership where like this belongs to you and you can change it. If it doesn't belong to you, you can't. And it's just interesting to me that we have these things where you have like Google docs where some people can edit things and some people can't. We have things like GitHub and Git where these massively distributed systems where people manage to collaborate all the time and not really tread too hard on each other's toes and it would be really delightful to have this in the core Ruby language. So how do we get these new concurrency primitives? This is going to require changes to Ruby. So I said we can look at guilds, we can look at implementing actors along the lines of what we saw in celluloid. We can steal things from Go because Go has been stealing things from us so it's only fair. And so you can kind of have this fetch method and if Lycos go get it, makes any sense to you, then congratulations, you are one of the grumpy old people that I was talking about and we can all hang out later on. And then you have this notion of okay, for each of these URLs, I'm going to go fetch and do something with them. So if I'm going to go fetch them, these are actually happening concurrently. There's no explicit spawning of a new thread. There's no explicit locking or anything like that. We just rely on the virtual machine to do this correctly for us. We could steal from Clojure. Clojure has this notion of software transactional memory where the software actually says if you try to do something and two of you are trying to change the same thing at the same time, somebody quits and tries again. You do get a little bit of overhead from these aborted and then retried operations but it turns out the performance here isn't that bad and you do get safety when you're working concurrently and so there's a method or function rather in Clojure called PMAP which is parallel map. There is some overhead because underneath the hood it's creating a thread pool and stuff like that and doing all kinds of dark Java magic. But again, this has abstracted the concurrency story away from you. You don't have to create threads manually. You don't have to create fibers manually. You don't have to think about it. You just know when I call this method or use this function, I'm going to have a concurrent. Basically, I'm gonna be doing a lot of things all at the same time and I as a programmer don't have to worry about that. So I think that definitely does. I said earlier, I was not sure if static types were in some way antithetical to Ruby's core message but I do think that this kind of borrowing new concurrency primitives from other languages is not in the sense that we definitely get developer benefit and we definitely maintain developer happiness because we don't have to think about threads. We just write code and it works. If you are actually interested in Clojure, I'm happy to talk about that later. If you're interested in how talks get written, this little bit of Clojure will tell you and even if you don't read Clojure, I think you'll get the idea. You pretty much just alternate between these two things and then at the end you have a talk. Although actually now that Matz has noted that we have Unicode, you can actually do it this way. And this is actually a lot more concise. So yeah, pretty much you drink coffee and freak out and drink coffee and freak out and then you stand up here. Yeah, it's as easy as that. I do, yay! Nearly done. So again, is this a good change or a bad change? If we keep the GVL then we maintain thread safety. We have all the protections that we have now at the cost of performance and we're probably going to start to see an asymptotic increase in performance where we start kind of hitting up against a ceiling. If we get rid of the GVL and we adopt another concurrency primitive or another way of handling shared mutable state, then we get true parallelism and a significant performance gain. Especially for CPU intensive work where you wanna be able to use all of your cores and do things at the same time. Again, this could be at the cost of safety. If you look into closure software transactional memory or I think there was a Watson paper a couple of years ago about hardware transactional memory actually relying on the processor to protect you. And they did it with Ruby and Rails and they saw substantial performance increases and I think they were actually in the process of looking at hotspots and they were gonna get an even better story together. I'm not sure if they published a new paper, but if you search I think Watson, Ruby, HTM or hardware transactional memory, you'll find that paper, it's not too long, it's very interesting. All right, so we're at the TLDPA which is the too long didn't pay attention. So if you just came in or you weren't paying attention, you can now get the whole talk in about 30 seconds. So types, there are a lot of different ways of handling static typing versus dynamic typing. What if Ruby had static types? I think what we're gonna shake out is there might be something to be gained by coming to gradual typing. Having the option to put type annotations into your code. In terms of the environment, there might be something to be gained by targeting WebAssembly. I hesitate to recommend source to source compilation although projects like Opal have been doing fantastic work and the sort of the less frequently you have to dig through the trans-compiled code, the better it is, I think. Though I'm really curious to see where WebAssembly goes. And then parallelism, I think there's room in Ruby 3 for all kinds of new concurrency primitives, whether we pick actors, whether we modify the threading story for guilds, whether we pick software, hardware transactional memory, but there's a huge number of opportunities and possibilities available to us. And I'm just really excited to see where it goes. So having said all of that, thanks so much for your time. I really appreciate it. Thank you.