 Okay, so I'm Patrick Farley. I'm a developer with ThoughtWorks and I'm going to be talking a little bit about Ruby internals. So to sort of be clear what I mean by Ruby internals, I've got some JRuby slides. I've got some Rubinius slides. But mostly what I've got is MRI stuff, that's Ruby interpreter. If you're not sure which version of Ruby you're using, you're almost certainly using MRI because it's what came on your MacBook Pro. I think a fair question is why you should care, right? It takes some work to sort of dig into this stuff. And so why, what sort of values are you really going to provide you? And I think to sort of address that question, what I want to do is look at some Ruby code. It's all, you know, it's sort of the wackier end of Ruby, but it's all pretty standard stuff really. So one of these things, I'm defining a module here and so I'm defining a method self.bar on the module foo. So anybody who's been doing Ruby for any amount of time knows immediately them in a bit of trouble. If I'm using modules here just in like their namespacing capacity, and so I'm putting together some sort of like function library or something like that, I'm just going to class it all under foo. I should be okay. But if I'm going to be using modules for their co-chairing capacity, right, this sort of multiple inheritance sort of thing, I'm in trouble, right? Because anyone that's been doing Ruby for any amount of time knows that when I try to include this module in a new class like Baz, I'm not going to get bar as a class method. And so we sort of all learn this as we first get to choose to Ruby. It's like, oh yeah, right, you can't bring class methods along when you include a module. But it's kind of strange, right? Like why is that? So similarly here, I'm just defining a basic module laughable with a method laugh. And this should look familiar to a lot of people. I'm just extending the class clown with laughable, and so I get a class method now laugh using the extend method. But interestingly, if I create a clown object, and then I extend that clown object with laughable, I get an instance method on clown. And so again, this is sort of something we take for granted, but it's a little weird, right? Like you've got a language that went to the trouble of giving you both length and size on array. Yet it seems to be overloading extend in this way that depending on the context you're using it, you're getting instance methods or you're getting class methods. Another kind of strange thing, right? This is one of the syntaxes you can use to define a class method. So a lot of people probably know you're basically opening up a singleton class here and you're defining a method, and then magically that becomes a class method. You know, the question is why is that true? Okay, so that's just insane, right? This is whiny nil from Rails. So if you call id on nil, it returns four. And so by default Ruby was returned four. What Rails does is sort of assumes that almost certainly this wasn't how you were planning to introduce the number four into your code base. You probably didn't want to do like three over id of nil. So it warns you, right? It throws an error and it's like, hey, by the way, you probably don't want to do that. Now that's really strange. So to sort of bring this around, just by a show of hands, who's read the pragmatic programmer in the room? The Ruby community is awesome, right? So I know it's, I'm preaching to the choir a little bit on it, but there's a section of the pragmatic programmer where the practice talk about programming by coincidence. And they talk about a programmer Fred. And the idea is that Fred writes some code and it works. And then he writes a little bit more code and it works. And then he writes some code and all his code stops working. And he can't figure out why and he tries to debug it and it goes to hell. And sort of the beautiful insight the practice had here is that, you know, the issue isn't that Fred can't figure out why his code doesn't work. The issue is that Fred really never knew why his code worked to begin with. So my contention is that, you know, there's actually, there's a decent amount of this going on in the Rails community, but not just the Rails community, the Ruby community too, when you start to get around some of the more advanced features of the language and you start to get into some metaprogramming. People are using stuff that they're seeing by example, but they don't actually really know why that's working. And I think there's kind of a craftsmanship issue there, right? It's beholden upon us to really understand the tools we're using and to not wait until we're sort of in that Fred moment. And I think we've all been there with metaprogramming tech stuff where it just doesn't work. And so we just sort of keep throwing stuff at it. And then eventually we kind of get it working. And the conclusion we draw is that metaprogramming is evil and that we probably shouldn't use it. So this is not an exhortation to use more metaprogramming, right? Like don't go crazy and metaprogram everything. I think the people that are sort of saying, you know, take it easy on the metaprogramming are right. But it's an important tool to have in your tool belt, especially if you're doing Ruby stuff around like DSLs or some of the more interesting stuff in that area. And so it's not enough, I think, just to know how to use it. You should know why it's working. So it turns out that a lot of the stuff around modules and mixins and metaclasses and singleton classes, what they've all got in common is that, well, they've all got method dispatch in common, basically. So there's a lot of ways that maths could have decided to implement instant specific behavior or mixins. But somewhere along the way, he or one of his colleagues, compatriots, made the decision and this sort of beautiful aesthetic decision that method dispatch was always going to work the same way in MRI, no matter what, no exceptions. So it makes out a beautiful decision is that that tightly constrains the implementation options for instant specific behavior, for class methods, for modules and mixins, and that's sort of our boon, right? Because what it means is that if you understand how method dispatch works in Ruby, it's very, I don't want to say it's trivial, but it's much easier to learn how all this other stuff works. As long as you understand that there's no exceptions, method dispatch always works the same way. You know, as long as I'm endorsing books, this is the Ruby hacking guide by Minero Aoki. It's written in Japanese. There's some partial translations online. He covers a lot of the material I'm hitting in the talk today. It's getting a little dated. I think it's 1.7x stuff. But it's still really interesting and if you like this stuff and you want to read more about it or review it, I'd encourage you to go Google and see if you can find the online versions of the partial translations. There's actually two partial translations. And if you know Japanese, I'd really encourage you to contribute to the project of getting it translated entirely to English. I think the community would really benefit from it. Other books I'm endorsing. I don't know if you guys know this book. That hurts pretty good. Okay, so let's talk about method dispatch. So I've got a ninja class here and it's got to be awesome method on it, which returns the symbol guitar solo. So I know it's a little silly, right? Why would guitar solo be a symbol? But I created this Bob class, this Bob instance of ninja and I call it be awesome. So the question is, how does the be awesome message end up getting attached to the method information found in be awesome? So what's funny is that I had a Darth Vader slide before the whole sombrero thing because it was sort of like C, right? And it's like evil but powerful. And then the sombrero thing happened and the problem is I'm really bad with like Gimp and Photoshop. And if you look at, you know, my slides, they're really minimal. It's not because I love minimal. It's like this is the best I can do. So I mean, I did, I got a sombrero and I tried for like a few hours to get it on him and I couldn't. So, you know, I cried and then I just gave up. But you see, he's like, he sort of cut off at the top so you can kind of imagine that there's a small, it's kind of like a Yamaka-like sombrero. Okay, so this is a C-struct, R-object. It stands for Ruby-object. So objects in Ruby are represented by the struct and, you know, everything's an object. So I'm not really talking here about arrays or hashes or classes. I'm more talking like, you know, the foo instance, right? Your standard kind of object. And when you look at it, I haven't reduced this at all. This is all there is to it. There's just two data elements. One is this basic, right, which is an R-basic struct which we'll get to. And the next thing is this ST table, IV table, right? So it looks kind of complicated. Oh, you know, and since we're getting it to see, who watches heroes? Okay, so you know like the brother and the sister is sort of annoying storyline and when she gets upset, her eyes get that black gook that sort of looks like, uncomfortably like the X-files black gook. And then like she holds her brother's hand and he's like, I'm here for you and it sort of goes away. I think it's sort of a similar thing with C and Ruby programmers. They look at the C and like their eyes just sort of start glazing over with this black gook. So just think of me as like the brother, right? So the second part, ST table, instance variable table, right? ST table is a hash implementation to see hash implementation. So all you're looking at is IV since we're instance variables, right? So what does Ruby know about an object? Well, one other thing that knows is what are its instance variables and they're stored in a hash right on the object. And the other, the only other thing it really knows about an object is what's in this R-basic. So take a look again. There's only two things here and I haven't reduced anything out. The first thing is an unsigned long flags. So basically MRI does a little bit of bit twiddling to keep track of it's like a properties collection, right? Are you frozen? Are you tainted? Are you singleton? A bunch of stuff and we'll get into some of it but not much of it and what if it's not all that fascinating. What's interesting is the next thing, value class, right? So value is actually here basically synonym for an unsigned long and depending on what class actually is and value gets passed around a lot in Ruby and most of the time it's a pointer, so a location of memory. It can actually really be a number. It can be a symbol. It can be a couple of other things but I think for our purposes and especially at this point in the talk the best thing is to sort of think of it as just a Ruby thing, right? So that's it, right? And since it's sort of this basic embedded in the object, there's really only three things that Ruby knows about an object. It knows about its instance variables. It knows about its class and has its properties collection. So it's really important is what's not here, right? There's no behavior. This isn't JavaScript, it's not a prototype based language. There's no place to store behavior on an object in Ruby. So when you think about, you know, I think a lot of these things like synonym classes and meta classes and all of this, a good way to think about them and learn about them is not, okay, what's a meta class? It's to ask the question, what does Ruby want? What does Matz want that forces this thing into existence? So when you think about classes in Ruby, just general classes, in a very real sense, they're places to store behavior, right? That's why they exist, because you can't store it on an object. And so when we talk about ninja and be awesome, we know that that behavior has got to be sitting somewhere following this class pointer. It's nowhere on that Bob ninja. So take a look at the struct that represents a class. So it's interesting, we talk about classes being objects in MRI or in Ruby. And it's like, yeah, sort of like from a usage perspective, certainly they are, at an implementation level, not really, right? It's actually a separate struct that's used. But if you look at the first two things on that class, you'll see one of them is again that basic, looks familiar, and again an instance variable table. So it's sort of like, yeah, it's not really an object, but it kind of fulfills the contract of objectness. But there are two important differences, right? It's two extra things on there. And one is another hash, which is the method table, right? So this is where all behavior lives. And then another value super, which is a super class in this class. So that's it. Our object, our basic, our class, it's really the only three structs you need to know to understand method dispatch in Ruby. So what's happening always, and in all cases, is a message is being sent to an object. The class pointer is being dereferenced. And the interpreter looks in the method table hash to see, can I find it, can I find this method in here? If you can't find it in there, it calls the super pointer and it looks in the method table it finds there. And it keeps calling super pointers until eventually it hits a null. And it says, okay, method missing, you know, I can't find this at all. So this is a diagram of sort of what it looks like of, you know, the object model, class model of Bob and Ninja. So you see it as a Bob class and when I send it a message, the class pointer is dereferenced and it looks in the method table I find in Ninja to find be awesome. If it didn't find it there, it would call super and go look on object and see if we could find something. So that's the actor that played Darth Vader, James Earl Jones. He also, he also does not have a sombrero. He could use one of his heads a little mashed up. So now we're going to send a method to dispatch. I want to talk a little bit about singleton classes and I'll talk about instant specific behavior. So here I have to find a new Ninja. His name is Joseph. There's a special thing about Joseph. Actually, he's really a pirate hiding as a ninja. So Joseph has this speak method defined on him and you know, if you're Ruby, you should be familiar with this deaf Joseph dot speak. This is how we add instant specific behavior. One of the ways you add instant specific behavior to an instance. So in this case, the speak method has been added directly to Joseph, right? And if you ask him to speak, he says R. If you ask Bob to speak, it's a good thing about ninjas, right? That's how silent they are. It's not like you ask them to speak and they say nothing. You ask them to speak, they're like, dude, I know she's talking about it. I can't speak. So how does this work? Right? It's because we just looked at these classes, these structs, right? And we know that Joseph is an object and we just define the speak method, but there's nowhere on Joseph to store that method. But we know that it's not living out on Ninja because if it was on Ninja, Bob could do it. So again, it's the question is why does Ruby want? So Ruby wants instant specific behavior, but it's constrained by the fact that method dispatch is going to work in only one way. So it's got to have a class with this behavior on. So what it does is something really relatively sneaky. It says on the fly, I'm going to create a new class just for Joseph. I'm going to stick that method right on there. I'm going to have the class pointer for Joseph point to this new class just for Joseph. And then we have it super point to Joseph's old class, Ninja. So this way, I still have Ninja classes and method dispatch is preserved and I got a nice sane chain. So this is sort of what it looks like before you define that instant specific method for Joseph, right? You've got Bob and Joseph the Ninjas and they're just hanging out being Ninjas. But then as soon as you define that speak method, behind the scenes the interpreter set defines this new class. And so you can read that apostrophe as a singleton class of Joseph. And so now the class pointer for Joseph points to it and it's super point there is pointing up to Ninja. So that's it. That's the whole mystery behind singleton classes, right? It's an instant specific class that's spun up at runtime dynamically when you try to add instant specific behavior. And starting this function RB singleton class. So this is a function when you try to access the singleton class. This is the function that gets called. So for instance if you were defining behavior or class less than less than self or anything that causes the interpreter to say hey, get me a singleton class. This function is going to get called with the object passed in. It's kind of long so bear with me. The first thing the interpreter does is say are you a fix num or a symbol? And some people have probably seen this before and won't allow you to find a singleton class on a fix num or symbol. And we'll get to why that is in a second. Actually the next slide because it's three other special cases, nil and false and true. So what's different about fix num, symbols, nil and false and true is that MRI sort of takes a performance shortcut with them. It doesn't want to do. So it actually represents all these things as real ints and passes them around as ints sort of disguised behind this value mask. So how can that be? Because you got to have all the numbers. So it does a bunch of funky stuff. Basically it bit shifts fix nums. So all odd numbers are represented by odd numbers. So that leaves it free with even numbers. Well false is usually zero and so it goes ahead and takes zero as false. But one can't be true because one is actually busy being used by zero actually. So it's got two. So if you do true dot ID, you're going to find an IRB, you're going to get two back. And then all it's got left for nil is four, right? And that's why whining nil is four because that's what it's got. Then it takes advantage of a really odd phenomenon which my comp side background isn't strong enough to understand. But with the allocation of objects and memory, objects are almost always going to be allocated in a memory space. It's going to be addressable by a number divisible by four. So the even numbers not divisible by four are free. And so that's where symbols will go. Bizarre but true. So fix nums and symbols which are sort of infinite in number or literally infinite in number, you just can't add in specific behavior to it all. For nil class, false and true, it does something special, right? There's actually only one true anyway, right? It's sort of meaningless to say the singleton class of true. True is a singleton in a sort of design pattern sense. Well, that's limited only by how large it is and how long it can go. Let's see how much true it is. I don't know, but it will be easy to think of true. So yeah, nil and false are true. They're really singletons in the sort of gang of four sense. There's only one of them in the entire system. So when you ask for the singleton on them, instead of really complaining, it sort of gamely plays along. But it just gives you back really the one and only instance of nil and the only instance of false and true. So the next thing it does is says, okay, well, you know, you're none of those things. How about, let me look at your class. Is your class already a singleton? And if it is and then we skip the attached piece of it, but it basically says, are you really the singleton I'm interested in? Are you really the one attached to this instance? And if it is, it just returns it. So it's already created, right? So this is what happens sort of after lazing instantiation. And if all that stuff fails, it calls RB make meta class, which is actually the function that creates a singleton. So this is the first time we're seeing the incredibly confusing nomenclature around singletons and meta classes and eigen classes and virtual classes. And unfortunately, that nomenclature is not consistent in literature. It's not consistent within the community. It's not consistent within various Ruby implementations. Like even in the source code. In fact, crazily, JR Ruby introduces yet a third meaning for meta class within their implementation. So the definitions I use, they basically pickax definitions and encourage other people to use is a singleton is an instant specific class. It's a class that provides instant specific behavior. Meta class is a class of a class, right? And sort of in the small talk sense. And those two things end up from an implementation perspective being very similar and very related. So you can sort of think of a meta class as sort of a special case of the singleton. It's the singleton for a class instance. I think that's the same as definition I've heard. If you've got a say no one I'd be interested in hearing it after five or six years. So and but it's not consistent even in the source code, right? So if you look at RB make meta class, I mean, even here this function is called whether or not you're creating a singleton class or meta class. Interestingly by RB singleton, which is called no matter what you're looking at. So I've actually elated some code from this for clarity. But what I've got is pretty straightforward here. Jumping back a second, you see what gets passed in to make meta class. It's the object and then the class of the object. So if this were Joseph, Joseph would go in and Ninja would go in. And when it gets into the class right away, even by parameter names, you can see what MRI is planning to do with it. It's planning to make Ninja the super and it's going to use the object so it can reset the class pointer. And so sure enough it does an RB class boot passing the super in and resets the class pointer and returns it. OK, so speaking of Ruby weirdness, right? How come this? So we just saw the diagram. We just saw the source code. We know this isn't true, right? We know Bob and Joseph have different classes. It's almost like Ruby's lying to us. Like it's hiding something from us. And that is true. It is hiding something from us. So include classes which are associated with modules and we're sort of going to get to those. And singleton classes are sort of like R2-D2 C3PO, right? When you ask Ruby about them they sort of like, oh yeah, nothing to see here. Move along. And where it does that is actually pretty straightforward and it's like nefarious, right? If you call dot class on something, this is a function that's really called when you call that class, RB object class. And it immediately delegates out to RB class real, right? The real class. And so what does real class do? Real class says, well let me take a look at your class. Is it a singleton or is it one of these things called an include class which are associated with modules? If it is, call super and go check out that thing and just keep calling super until you find me a class that isn't a singleton and isn't an include class and return that back and that's going to be the real class. So my talk was sort of running a little long. There's sort of some interesting background on why this is not, you know, it used to make me furious, right? And it's actually not that bad an idea. It has some, if you think about quality semantics it has some interesting implications in Kentback actually wrote some great articles and small talk report in the 90s, early 90s about this stuff. So if we finish early or again, if you can catch me tonight I can tell you about it and it's sort of interesting. So let's talk about the meta class which is sort of like the shadowy I don't know the metaphor starts to fall apart but. So again, meta classes, right? Instead of talking about what a meta class is maybe it's better to talk about why you have a meta class at all and the answer is Ruby wants you to have class methods, right? And if you think about method dispatch again what is method dispatch says? It says when you send a message to an object I'm gonna dereference its class pointer and I'm gonna follow a super chain and remember no exceptions, right? So that means class methods too and when you think about what a class method is it's just a method sitting on a it's sitting on a class itself and so when you send a message you're sending a message to a class Ruby doesn't care it's saying that's method dispatch. So you know what certainly maths could have done is you could have stuck these methods right you've got a method table, right? You've got a place, you've got a hash restoring methods and you could have used some wacky thing for disambiguating class methods versus instance methods in that hash but he doesn't, right? And that's the beauty of it. Instead he uses that R basic and he finds the class in there and method dispatch follows it out to find a meta class, right? So this is, if that were all there was to it this diagram would be accurate there's actually more and we'll get to it but just looking at it for a second it actually sort of makes a beautiful sick sort of sense, right? When you say, what is the pirate class? It's an instance of class, right? You've got all these instances of class running around in your Ruby process and now you want to add methods to them. So what are those methods? Well, they're methods that are specific to specific instances of class. You don't want them to be in class because you don't want all classes to have them. You just want your instance of class, pirate to have it. So in a very real sense a class method is instance specific behavior. It's just instance specific behavior that's specific to class objects. So this is why a meta class is really a singleton class and that would sort of be the end of the story if that's all Ruby wanted but Ruby says classes are objects and if they're going to be objects they get to play polymorphically, right? So let's say we added, let's say we had pirate subclass human, right? And so things would look a little like this and then if things worked consistently with everything we've been talking about so far we would say, well humans an instance of class so humans got a meta class and it's super point to points to class. So there's a couple problems here, right? If I define a class method on human now there's no way for method dispatch to get to that method if I send the message to pirate because it skips completely over the meta class of human. Also that diagram is ugly which is sort of a good sign that you've gone astray somewhere. So what Ruby does is actually it does something a little sneaky here. It says, well I'm going to make meta classes work a little bit different than a regular singleton class. So instead of just moving the class pointer I'm going to pursue this sort of parallel inheritance hierarchy and I'm going to have, I'm going to say well if you've got a super then your meta class is super points to the meta class of your super, right? So that's actually there's like a Zen cone there, right? There's like some mountains outside it's just climbing one and thinking about the super of your meta class is the meta class of your super and eventually, you know, enlightenment. So this is actually what it looks like and again, diagrams prettier, right? So it's, I mean by my standards. So it's a sign that things are on the right path and this is exactly how it works and what's nice about it is you get polymorphism on the classes and method dispatch gets to continue to act exactly the way it should. But don't take my word for it this is actually where the singleton classes versus meta classes are created. Singleton classes in that RB singleton class meta classes interestingly in RB define class ID. And so if you look at the second parameter the difference between what gets passed into this function in the first case, I'm saying hey, give me the class of the object. In the second case, I'm saying hey, give me the class of the super of the object which happens to be a class, right? Another sort of interesting difference between meta classes and singleton classes and it's sort of just implementation but singleton classes get created dynamically at runtime when you try to add instant specific behavior to an object. Meta classes that singleton classes of classes get created as soon as you define the class. So you see it's RB defined class ID there basically as soon as you assign a name a constant to that class, up goes your meta class. So it puts us in a good position to understand what's going on with extend now, right? If you look at the implementation of extend all extend does is actually it calls include it's the same thing except it says include on my singleton class. And so if you call it on an instance and you call include on my singleton class now you're getting that special singleton class spun up and you're getting instant specific behavior and you're getting instance methods added. If you call it on a class singleton class returns the meta class, right? And so it's being included into that inheritance hierarchy and so you're getting class methods. So actually extend does exactly the same thing it's just depending on the context it's very different meanings for you. So I showed you some diagrams and I showed you pirate pointing to human and the meta class of pirate pointing to the meta class of human which pointed directly at class. It's not really true. The message of the slide is don't trust me don't trust Landel Calvarsian. Because it actually, you know we all know that the base class for all classes in Ruby is object. And if this parallel inheritance hierarchy is gonna be maintained then we've got to have human pointing to the meta class of objects. And that is exactly what happens actually. So this is actually much more accurate and from here you start to get into probably familiar territory for most people. Class points up to module because class descends from module. But you start to get into a little bit of trouble when you call inspect on pirate. So inspect is an object instance method and you're talking to a class. So if you look at the diagram again it's okay this is living in the upper left hand corner there in object and I know that from a high level we say classes are objects but from a low level method dispatch level how are we getting all the way from that upper right hand corner of module over to object? You'd have to do something crazy, right? You'd have to have like the super pointer on module point all the way back over to object. And in fact that's exactly how it works. This also explains why if you jump into IRB and you add an instance method to object you'll find that immediately available as a class method on objects which is also weird until you understand how this is working. Now that is crazy but this man got Mark Hamill's face tattooed on his back. So it's a crazy world. Okay so we'll talk a little bit about modules and mixins. It's pretty straightforward. I've got a useful module. I've got a class. I need a little help that mixes in useful. And so when I create a new need a little help I get access to share me and I get working hard. Again I don't think anyone in this room would find anything about this the least bit surprising. But if you think about how I've said method dispatch works and my promise that it never works anyway but that it gets a little bit surprising, right? People talk about, they talk about mixins as being you kind of hear two things, right? You hear well it's sort of like multiple inheritance and it's sort of like an abstract base class. Well if method dispatch is gonna work correctly that means that when I call super on need a little help I need to get to a class, I need to get to the mixin, right? I need to get to a hash that includes all the behavior I'm looking for from that module. So that basically is what happens, right? And this diagram sort of gets more accurate as we go along but roughly useful is being inserted into the inheritance chain between object and need a little help. So I would say if you're talking is it multiple inheritance, is it an abstract base class? Well it's neither but it's a lot closer to an abstract base class than anything else. And what's interesting about it is it's an abstract base class that gets sort of mixed into your inheritance hierarchy on the fly when you request it. So continuing on, right? You can of course include a module into a class which has a super class. And so that module ends up sitting somewhere right between your class and your super class. Again, it should be surprising really. If I define a method in a module and mix it into a class, it's gonna replace the method of the super class, right? It's gonna sort of override it. But now we know what's really happening. It's not really replacing that method in any meaningful sense. All that's happening is that method dispatch is good to go looking for that method. It's good to client super pointers and it's good to find it in the module before it ever gets up to your super class. So it just never bothers to check if you might happen to have another implementation somewhere higher up on the chain. Of course you can mix multiple modules into a class and what happens is that module will get added to your inheritance chain right above the class. So you start building up this stack that's building up from the bottom and it looks something like this. So so far all good. It makes a lot of sense. The problem is that you can create another class and you can mix those same modules in and you can reverse the order of them. So what does the inheritance hierarchy look like here? We've got mix and module pointing to another mix in with its super for this ono box. But wait a second, right? We just looked at this class and we saw that those super pointers work the other way. So what's happening, right? We've only got one Ruby process and it would be really bad if you mix in a module into a class it screwed up all your inheritance hierarchies all over the place. So Ruby's got to do something special, right? And again it's a similar thing, it's constrained. Method dispatch can only work a certain way or it is only going to work a certain way. But the interpreter wants you to have a way to share behavior but maintain separate inheritance hierarchies based on where that behavior is located. And so it does something very, very similar actually to a singleton class. On the fly dynamically it spins up a brand new class for you and that brand new class it spins up is called an include class or an eye class. And the whole point of this class is to wrap module behavior. And so the method table, it doesn't actually have its own method table. What its method table really is, is a pointer to the module's method table. So what that buys you is that if you update and change the module and you change the behavior there wherever that module is included you're cool, right? Because method dispatch is going to climb it's going to find this include class it's going to look at its method table that method table points to the real module's method table. Yeah, it includes it's sort of like I'm not really at all actually. So this is include class new. It's also the last significant block of C code to look at, which is good I think. So if you look at the first two sort of meaningful lines in the function there, what's going on? First a new class is being created a new instance of the struct R class. So these include classes from MRI's perspective really are classes, right? They only have what a class has and nothing else which ends up sort of being important. And the next thing it does is it sets up the object and you look at last piece it's sort of telling TI class that stands for type include class. So when we talked about that flags collection sitting in a basic that's one of the things that gets stored there, right? So this is how the interpreter's going to know like for instance when you're looking for real class that this class is an instance of include class not a real class by Ruby's definition. And then if you look at what happens with the method table on the next line the method table of the class, this new class, this include class is set to the method table of the actual module. And supers are set much like a singleton class so that you get inheritance chain sanity. And then right before you leave something a little strange happens. The class of this new include class is set to the actual module. So the issue is the interpreter every once in a while wants to know hey what module are you really? And remember this include class is a class struct. It doesn't have a lot of spots to put that in fact it's got exactly one, the class data member. And you know it uses this like ancestors would be a good example if you're ancestors and you see everything that's gonna mixed in well that's how it knows. But that has profound implications, right? Because normally what is the class, right? The class of the class is only the meta class and it's where your class methods go. In this case the class of your include class is the module. So this is a pretty accurate look at what you look like after you've moved useful in after you've included useful into need a little help. So need a little help super pointer points to an include class for useful. And that include class for useful is just like this, you know, shallow proxy thin wrapper thing that doesn't do much except hang out and be there and have a super pointer. Because it's method table points over to useful, it's class points over to useful and it's super points up to object. But what's important is that that super is free to be manipulated just for need a little help. So let's jump back over to defining class methods on modules. This would start to make some sense. If you think about what's going on when I define self.class method here, what I'm saying is, hey, there's a useful module that module has a meta class and I'm gonna stick a method on it. But if I look at what's going on with class hierarchies here, right? Starting with need a little help in the lower left hand corner there, right? If I send a message to it, class gets dereferenced, I end up at the meta class and need a little help, right? Or apostrophe need a little help there. Then method dispatch calls super and it ends up way up on meta class of object. It never sees useful, right? We're just sitting sort of in the center there and it actually doesn't even matter if it sees useful because useful is not even what you want, right? What you really want is meta class if useful is way off on the right and there's no way to see it. Which explains this idiom, which I assume most people are familiar with. So this is how you get class methods in besides extend. If you wanna include both instance methods and class methods, you implement the included hook. And what the included hook, what you do in the included hook is you say, hey, when this module gets included in the class, that's to say instance methods are added. I also want you to extend its class with this other module I've defined here, class methods. So when you look at what that looks like, complicated and weird and a little hacky, but it's getting you what you want, right? So now when you call a method on need a little help, class is dereferenced and you find meta class in need a little help, the super pointer is pointing to a brand new include class, but this include class is an include class for class methods. And a super pointer points to meta class of objects. Okay, we're gonna look at some Java. But it's actually JRuby, right? So I thought, it's not fair because it's sort of like, well, yeah, it's ugly, but it's also kind of sexy. So it's more like this. So something for the ladies. Inclusive. I know people like, well, that's not really that sexy, but I mean, it's Carrie Fisher, right? So, so this is JRuby's implementation of a Ruby object. The JRuby code base is a very fast moving target. This is accurate as of last night on trunk, which is what I was doing instead of putting some barrels on Darth Vader. You can argue my values. My value system is my off base. Anyway, if you look at this object, you see there's actually a pretty tight mapping, right? You're in an OO language and so you get some good stuff now, but you see there's a Ruby class meta class. So this is where JRuby incredibly has redefined what meta class means again. And in this case, a meta class in JRuby is really saying, well, this is your Ruby class, right? Because you've got a Java class. So this meta class instance variable isn't a meta class, right? It's just your class, but it's your Ruby class, right? So if you think of what that struct looked like in objects, you sort of knew two interesting things about a struct. You knew what its class was and you had a hash with instance variables in it. And so you actually have the exact same thing going on in JRuby. You know what its class is and then you've got this array variable table entry, which is your instance variables. And of course, Java is an OO, so you don't have to do a lot of chicanery. You can just say module or rather class extends module and you can put your stuff right into module. And if you look at module, you know, it's amazing. As more features get added to Java, it looks like it becomes as unreadable as C. It's wild. So but if you really look at it, you can see there's a concurrent hash map here, right? So this is called methods. So it's basically a hash with methods in it. And if you look at the second thing there, you've got a Ruby class, super class. So again, the mapping is actually pretty tight one to one here, right? You're saying, hey, a Ruby module, which is really the thing that class inherits from, it only knows about two things. It knows about methods and it knows about its super class. And it itself is an object, which is cool in Java because I can just extend Ruby objects. So unlike MRI and JRuby, a Ruby class and a Ruby module really is an object. So, you know, speaking of fast moving targets, this is what this code looked like, I don't know, like four months ago or something like that, maybe a little longer. So the point is, I mean, I think the JRuby guys made a great, and by the way, JRuby's fantastic. If you haven't checked out, you should. But they made, you know, a really good decision. I think, you know, reasonable decision, they said, first we're gonna make it work and then we're gonna make it fast. And now it works, and now it's actually pretty fast too, but the difference is, right, they're doing performance optimizations and that's where you start, you go from this to this. Whoops. You go from this to this. So if you are interested in JRuby, if you're interested in how the internals work, it's sort of employee to get involved now because as they start to look at more and more performance optimization tricks and compiling more and more stuff down directly to bytecode, it's gonna get more complicated. You know, one of the sort of, I don't know, virtues of it is that it started as a direct port of the MRI interpreter, so it's actually mapped pretty tightly, one to one. But that's, I mean, very quickly becoming not true. Okay, so Boba Fett, who is the coolest character in the Star Wars universe, and I think probably the coolest Ruby implementation these days is Rabinius. But you know, it's crazy, like, I thought, well, there's no way I could put this hat on Darth Vader. So instead, I haven't really had a chance to dig too much into Rabinius, but let me do that and I can come up with some stuff and really, it's really different, right? Because it's a ground up re-implementation. So I could have put a hat and a poncho and a Budo for Vader and I still wouldn't have really gotten anywhere. But there is some interesting stuff with a method dispatch that I pulled out that I think is worth looking at, right? So because at the end of the day, Rabinius has to solve the same problems. So if you look, and what's nice is it's Ruby. If you look at find method in hierarchy, right? So this is sitting in module and this is method dispatch. And the first thing it does is it looks at a local hash and says, hey, there's a method here. And if you can't find it there, it calls direct to superclass and says find method in hierarchy, right? So this is basically the equivalent code going on here. And then it does something kind of wacky. It actually checks directly on object and kernel to see if it can find the method. I don't actually know why that happens, why it just isn't part of normal dispatch, that's like exercise for the reader. If you look at the implementation of find class method in hierarchy on module, so what's different about this is that the actual module knows about class methods. So it doesn't immediately go out and say, hey, my class handle this message that was sent directly to me because I never handle anything sent right to me. It actually knows about it. But if you look at what it does when you call a class method, it's basically the same thing again, right? It's self.metaclass.find method in hierarchy. So choosing the same dispatch mechanism, it's just passing off to the meta class to find it. You talk about Ruby being expressive. This is fantastic. This is class initialization. I've elated a bunch of code to sort of make the point. But if you look, you pass in the super class when you create a new class, so nothing too surprising there. And you sign it to an instance variable. And then you grab your meta class, which is called MC. And then look what you do, right? And the easiest way to read this is probably backwards. And it says the meta class of the super class is the super class of the meta class, right? That's awesome, right? You talk about Ruby being expressive language. That's it right there. As a Star Wars character, it looks the least like me. Um... That's pretty much all I've got. And it looks like I've got some good time for questions. Just by quick show of hands, is anybody interested in equality semantics and why the real class is hidden? All right, sorry. So this is, like I was saying, it used to drive me nuts because I pulled it out of my deck because it was taking too long, but I kept it just in case. Yeah, it was driving me nuts and whatever, that was sort of the end of it. And then I was reading some old small talk report articles by Kent Beck. And there's sort of nothing new under the sun, right? Turns out in 1993, he wrote a couple articles about adding instant specific behavior to small talk. So small talk out of the box is meta classes, but it doesn't really have a singleton class in the sense of, well, let me, at least this is my understanding of it. I'm not a small talk guru, but you don't have this instant specific behavior. But it's pretty easy to roll your own. And over the course of two articles, he talks about rolling your own instant specific behavior and surprise, the implementation is almost exactly what you're doing in a Ruby, right? Instead of a class, it's a behavior. But on the fly, you create a new behavior, you change the class of the object to be this new behavior and you have it super point or point to its old class, right? Almost exactly what happens in Ruby. So everything's cool, but in 1995, he publishes another article in small talk report and he's sort of like, oh, time out, there's actually a problem with that thing I told you to do. And this is the example he uses. He says, imagine you have a point. So these are pretty reasonable equality semantics for a point, right? You say, are you both points? And then you say, is your X the same and is your Y the same? So think about what happens with instant specific behavior and singleton classes, right? If you switch out the point, if you add a new method to one of the points, its class is different, and so it's gonna fail that first test. So those first two points aren't gonna be equal anymore. So it's sort of kind of an interesting philosophical language design decision you're gonna make here, right? Because from a pure standpoint, that's completely accurate, right? Those points are not the same anymore. One of them is capable of behavior that the other point is not. But there is kind of a pragmatic approach and that is an absolutely reasonable viewpoint to have. But there's a pragmatic angle on it, right? Which is that we're gonna use frameworks and we're gonna use the libraries and we're gonna use each other's code. And if things were gonna work this way, what that would really mean is it would never be safe for me to add instant specific behavior to an instance of a class that I didn't define and have complete control over. Because what could happen is if you handed me the class and I added some instant specific behavior on it, equality would start failing. And God knows where you're using equality or how you're using it and God helped me when I go try to find that bug. So what Kent Beck suggests is pretty interesting, right? It's almost exactly what Ruby does. It's this idea of a real class, right? And so you'll have your, slightly different. But at the end of the day, what he's suggesting is have your class return an actual real class. And then if you want, add a dot meta class or I forget what he calls it, but essentially add another method on there which will give this instant specific class. So anyway, once I read those articles, it's weird. It's like, you know, who would have thought useful to read an article from 1993 in a sort of small language. But yeah, I felt better about it. So I've got about 10 minutes for questions. I just want to say to the results, sorry, but you need 200 gigabytes of RAM or swabs to install some similar things. Like, you weren't able to do it? We had 65 mil running on this machine. I've taken three games for it in a month. So that's when our machine started dying. We calculated it to face the whole grade and we were able to do it with that crash-arm machine. The campaign. I think we'll see you in a minute or two in the street. And we'll go to a place set. Yeah. Any other questions?