 My name is Jeremy McNally. I've written a lot of open source software. This is a little bit of it. I didn't get a sound feed, so you guys can't enjoy the experience like I can, but... I think I got it. Please, I have to sit here. It's in, but I'm not sure if it's... Maybe if you... Oh, come on. There we go. Okay, that ruined the whole riff-roll surprise there, but it's okay. It's okay. Yeah, yeah, it's like rake-showing. I don't know what you'd call that. But I've written a couple of books. You might have seen the Mr. Yang-Billy book floating around the internet, and I can almost guarantee you none of you have seen the Ruby in Practice book because it's not out yet. But it's done, and it's baking, or whatever it is they do in production, and it should be out soon. And whichever one of you guys I like best can have two copies of it. I have no objective standard for deciding who gets those, but I'm told by my publisher I can give away two. So... I work at ENTP with Rick Olson and Justin Palmer and Courtney Gasky, and I organized the Ruby Hoedown that I've spoken in a few other conferences. So we're going to be doing a talk called Deep Ruby, and it's going to be more of a meta-level talk, a little bit below the level of Giles' talk earlier. It's going to be more of a talking about Ruby's object model. And I'm sure a lot of you are looking at Deep Ruby and thinking, what are you talking about? So I'm going to use the Chronicles of Narnia here. You know, when Aslan and Edmund are talking, there's that, what's the kid's name? Edmund? Yeah. Yeah, that's the one. They're talking, and it's sort of like Jesus into the Cycles. Aslan's all like Deep Magic, and then Edmund's all like, what? So we're going to try to answer a lot of the questions about the object model. If you have any questions, by the way, just raise your hand. If I don't get to you, yell at me. If I still don't answer, just wave your arms wildly or throw things, and I'll eventually get around to it. I really wanted to give this talk because, well, frankly, you may or may not suck at really using objects in Ruby. And I kind of suck at it a lot of times. I don't really think about how I could best exploit Ruby's object model. And we all suck. And if I was really cool, you could insert a clever spoof of you suck at Photoshop. But unfortunately, I'm not skilled with iMovie, and it defeated me. So this talk's not going to be a bunch of object graphs and discussions in UML. None of that, not going to abuse you with that. We're going to talk more about, I guess you could call it the flavor of Ruby. Maybe that's salt, by the way. Talk more about what makes Ruby Ruby. You know, when someone talks about Ruby, it's like Lisp. Like, what makes a Ruby Ruby? So I'm going to set up a metaphysical framework here. That's sort of what we're going for. That would be us. And that's Ruby. So let's just jump into just basics of Ruby objects. You know, we talk about objects in everyday life. Things we use, shoes, for example. Computers, things we manipulate. Objects, you know, things that exist in our space. In Ruby, everything is an object. Classes are objects. Numbers are objects. Objects are objects, if that even makes sense. But when we talk about objects, we have all these languages that are totally object-oriented, prototype, object-oriented languages. And then we have all these languages that talk about having object-oriented features. And a lot of people get really confused when you start talking about objects, because there are so many definitions of what makes an object. In Ruby, everything is an object for real. Like, seriously, it's not lying like Python. You know, where it's like, everything's an object, except we have these few little methods that just kind of mess around with objects, but they don't really belong to the object themselves. And I know there's some Ruby internals geek out there. It's like, that's not right. You are not correct. And that's true, because in the C implementation, classes are technically not objects. They're their own struct and stuff that we don't really care about. But when we're usually using it, everything's an object, because we can work with it. And so what's the difference? I guess in a language like C-sharp, you could really think of objects as bricks. You know, you kind of have this thing, and you can't really do anything with it. You can't do stuff, but it itself is pretty solid. In Ruby, you can more or less think of them as Lego bricks. And those are not Duplo blocks. For those of you who have read that blog entry, they're Lego bricks. And you can build with them, you can manipulate them, you can snap them together, work with them, compose different things with them. It's a different mindset when you're working with objects. In Ruby, the objects are more or less defined by their behavior rather than a class, because at runtime you can change things. This is totally dynamic behavior on the part of objects. And so it's not really like something like C-sharp, where there's very little about the class or object that you're working with that you can change at runtime other than properties or state-related values. And this behavior creates the protocols for interaction. So whereas in a language that is statically typed and strongly typed, you have your class, and that's what defines what that object can do and what it can work with. In Ruby, it's defined by its behavior. And so if something has a method and behaves a certain way, then it can work in that context. When you work with a language like C-sharp or any of the statically typed object-oriented languages, you get code that's a lot like a pile of Lego bricks. It's broken up, it doesn't really work cohesively as well as you could if you had a little bit looser typing system. You get things like that where it's convert array to stream, convert hash to stream. There's very little that you can do, and in many situations you can use polymorphism in this, but in a typical situation everyday development, you're not going to want to build your object model around thinking, what can I do to save code? It just gets in the way when you start putting things together. In Ruby, on the other hand, you can build cohesive systems. You can kind of snap these little bricks together and compose different things. The example we just saw, and this is really contrived, but he's doing innumerable 2S. And if it responded to the each method and took a block, then it would work with this method, whether it's an array or a hash or a set or anything that is innumerable that has each method, then it would work with it. In Ruby, as you start building these protocols, you start laying bricks in place, you start conforming to the protocols of other objects for interaction, so you have those that can come down as you conform to more and more of the protocol than you have other objects that you can begin to interact with in a meaningful way. Or you could build your object protocols like this. Okay, we're done with that. In Ruby's object model, favors composition that way, whereas in a lot of object models, your thought process centered around inheritance and building classes up that way. Ruby is more about composing classes of modules and building up from the ground up rather than top down. So since they're defined by behavior, I thought we'd discuss the behavior and what you can do with it. It makes a really interesting code. Open classes and module composition are really, really powerful mechanics if you take hold of them and really use them. This is not a very good use of open classes, but it is one that demonstrates the point. You can open the class string up and just slap a method in there. If you've ever looked in active support, they do this a lot for various scenes, a huge library of really actually helpful methods in there. I am not against this sort of patching so long as it's documented and everyone knows about it, and it doesn't change behavior but only adds it. Then that's when you use something like this. You could also do something like this. This is a very common idiom for plugins when they're adding methods and behavior to active record. They will create a module, put all their stuff in there, and then you send to tell active record base or whatever to include it. Now, that's a really good thing to use, but in most cases it can be really bad too, especially if you're distributing this code to other people because they may not know about the behavior you need to change or add it or they may add their own behavior that's similar to yours or whatever. Ruby's object model is kind of set up to let you change a single object's behavior. David Black is a big fan of this one and his chapter 13 of his book has been really helpful in making me understand this. You thought when I talked about reaching for, altering a single object's behavior, I was going to go for instant C val, didn't you? Who thought instant C val when I said that? Okay, not a single person, so that's not as offensive, but it's actually really good. The Singleton classes can actually give you a little bit more flexibility and they definitely perform better. They're kind of stressing the limits of this stuff and using a Singleton class rather than instant C val just to add behavior was about five to ten times faster than doing a lot of instant evaluation. And you've seen this Singleton class thing before. You've seen class, bracket, angle, angle, bracket, self, and then adding things like that to add class methods. It's the same thing. Since classes are objects in Ruby, what you're doing there is you're saying inside this class body, self is the class object. And so this class less than idiom adds behavior to that object. And so when you do that, you're adding a method to that class. You can do this with normal objects also. You don't do it with just class objects. We have a string and I add the Pandemania method to the string and then I call it just on that string. But if I create a new string, you can call it. It doesn't know about that method because that Singleton class hasn't been created for that object. And I talk about, you know, not really advocating instant C val. It's great. I use it if you look in my code. I actually use it quite a bit because there are some situations where it's kind of essential. But I don't really advocate it. But if you really need to use it, you can. There's nothing wrong with it. Ruby is really dynamic. Its objects are obviously dynamic as we discussed. David Black says saying Ruby is dynamic is kind of like saying Ruby is Ruby. They're sort of one and the same. And it's really conducive in the way it operates to doing a lot of dynamic programming. I've talked about extending objects. The open class is just being able to totally manipulate classes and the class objects at runtime. And there's also dynamic duck typing. It's not really the same thing with the same sort of idea where you have classes of, you know, here are three types, foobar and baz, and they all respond to the speak method. And I'm using all three of them in the same bit of code rather than having to write new methods for each one of them. As I said, your code could be dynamic using all the eval methods. I'm talking like zig-ziggler dynamic. Seriously dynamic here. At this point, the Ruby interpreter acts as glue. I mean, you're not really dealing with something that's like telling you how to operate your code. It's just sort of the space that you can operate in and totally change the way anything operates, evaluate code on the fly, change the way individual objects, individual classes operate. It's just sort of this glue that sort of glues your object interactions together. Now the eval family of methods can be really useful if you're not familiar with them. There's class eval, which adds behavior to a certain class. And so I've added some behavior to the theme class here. And when I run the make shiny method, then it adds a method that is shiny and it returns true if it's defined. There's also module eval, which is its alias and less attractive cousin. And then there's instance eval, which I discussed before that lets you alter a single object. In this case, I went back to the object that did not have an is shiny method and added it back in there, returning false, since that is in fact not a shiny thing. Just don't abuse them. If I see code like this, and anyone's open source repository, I may become very angry and be prone to throw things like your house. And I will abuse you if you abuse these methods. And I will call this guy and we will come to your house and I will let him rough you up and give you an inspirational talk about staying in school. But before we move further, we probably need to stop and talk a little bit about other methods that you can use. You don't necessarily have to use instance eval most of the time. There are a lot of methods on object, on kernel, on class, on module that let you do the same kind of things without actually using instance or class eval. You can't do everything with these, but you can do some things. And I sort of advocate doing that because it makes it clear, like there's defined method that lets you obviously define a method. But if you do it in instance eval, you kind of have to parse code, think about what you're doing, backtrack, figure out if that's the right thing to do. If you have defined method or instance variable set, then it makes a lot more sense to be using that if that's all you're doing. And this is all kind of cool and sort of meta and everybody likes meta programming because it's a good resume bullet point and every Web 2.0 company has that on their job listings these days. But it's really practical also. It's a really good way to save code. It's not one of these things where it's beautiful but you can't justify its existence. It's like, what is that? I don't even know. And then there are things that are just beautiful and self-destructive. And it's just kind of, I mean, it's sad to see. And then there are things that are beautiful and functional. If you've never sat in one of these chairs, go to your nearest Herman Miller dealer and just have a seat because they're heaven. And they're also $5,000. So if anyone wants to buy me one, I'll give you my book. That's how you get a copy. And so they're really good at drying up code. This is some code that's pretty similar to what I had in my decub utility. What decub does is it takes all of your modules and classes and stuff and it hooks into RDoC and just sort of surgically wedges itself in there and checks for documentation coverage, just like RCov tests for test coverage. And this is some really stupidly written code that I had in there that was not really stupid. I mean, it made sense to me at the time, obviously. Modules, classes, and methods, I iterated each of those because they had a different method for getting their name. One was module name, one was class name, one was name. And so it made perfect sense. And then Chad Fowler smacked me in the face. I really think he probably would have if he were in person and told me to refactor it this way. Any class in any module are what RDoC calls the class of module objects once they've parsed it and gotten the documentation out. And so what I did is I opened those up, created a name method and told it to return its class-specific name method when I asked for a name. And so now I can do one loop instead of three separate ones and plus the code makes just a lot more sense that way. And also make things pretty. There's going to be a talk about that right after this one as far as I can tell with domain-specific languages. And, you know, RSpec is a pretty good example of a domain-specific language. It's not really English, as Dave Thomas said. It's just broken English if you try to make a DSL that's just pure English. And so this is a really nice language that is very domain-specific. Someone who works in that domain is going to understand it really easily. And these sort of features of Ruby are what make that possible. You can change behavior without changing the class. I like to call it monkeying without patching or raping or punching or whatever it is you could call it these days. This is just back to the per-object behavior that I talked about earlier. This is something that we do on a project that I'm working on now. We have models. And that model is going to operate in a lot of different contexts. If this is interacting with a lot of different web services and so instead of having eight different models or sending the model object off to a random method, we have these modules that encompass all the functionality we need to fully interact with that web service. And each time we interact with one of the different web services, we include the methods that we need to talk to them. So there may be an upload method in every web service module that is included back into that model class each time on the individual object rather than the class and executed rather than having a bunch of different methods and a monolithic class floating around. It's also good for object composition and you don't really hear that term a lot in Ruby, but when you do things like validations, things like axes attachment or attachment foo, these little metaprogrammed helpers, when they use the right way are a really nice way to compose your object's behavior without abusing the system. That's really about it. I wanted to leave a lot of time open for questions because I heard a lot of people talking about how some of the stuff covered in Giles talk was a little bit over their head or they had some questions about some of this. So, yeah, that was fancy. That's a key note right there. So if anyone has any questions. So if you're going to get into this later or if you don't want to slow the rest of the class down, you're welcome to skip over this question. You mentioned don't use instance eval or send favor the single class. Why? It's a lot slower and the problem with instance eval is a lot of times people like to go crazy with it and there's nothing, like I said, there's nothing inherently wrong with it. It's just in most situations you don't need it. If you're just doing some constant behavior like enumerable, there's no reason to use instance eval for that and I don't think they do, but you're adding each and next and first and all that to the class. And so, since you're not having any sort of dynamic names in Rails it makes sense because, you know, has or find or create by, those are dynamically created methods that they instance eval because it's find or create by name and so you wouldn't want to go through all the attributes and pick all these names out and define all those methods. It just makes sense to instance eval it. So in general the single class makes more sense but in some cases it makes more sense to instance eval. If you eval at the cost of speed does it give you more flexibility that way? You can inject. Since you can use a string of code you can put your own values in there like the find or create by name. It's find or create by substitution, you know, whatever the property that you're looking for is. Anyone else? Nobody? Okay. That's all I have. It's hoping for more questions but it's quick. What? No. If you use that on an object, like my object method name, is that as different than... No, it's the same idea. Yeah, I didn't show that in there but it's the same idea. It's still adding the behavior to that certain object and it's the same thing if you do it with a class too. Do you know if it's optimized like that and what you're doing with it? I don't know. I don't know. I don't know. I don't know. I don't know if we're really saying this or that thing but... What kind of stuff in my talk was over... I never saw the pre-guided idea just saying that it was basically ultimately awesome. Oh, thank you. Yeah. It was a lot of high level metaprogramming kind of stuff so... But that would indicate they understood it, right? No? No. I don't know what it was. They expected it, I think, going into that talk and I really enjoyed it but... Yeah. For someone who's getting into this, what would it look to you in this course? Maybe I have the one challenge. I hope the new paybacks... I don't know if they probably updated that and had a lot of content in that area since it's sort of become more interesting since where else has exploited every possible avenue for that sort of behavior. I don't really know. I don't know if they're the third edition. They might be able to speak to that but... No, it's still a pretty much out there and it's included in the exploit and it's included in the extended of the context. Okay. Right. Right. Right. And at the early way I think it has some material on it, but David Black's book is really good about that one chapter is just excellent. Yeah. Yeah. The technique where you re-enact significant methods into particular objects that you showed towards the end there, I've learned that in some cases that I've had a serious grief and I don't know if it's a bobbin ruby or if it's defying behavior but when you have a case statement that discriminates on the classical of the object, sometimes it gets confused and you can't call it a classic because you've got to modify the single from the classic. Yeah, a single. It creates a weird single and inner class kind of thing and it's not the same. David Black talks about that in his book and he says that it's going to show up in ancestors so that might be a good way to balance it out, like merge the class and everybody in the ancestors. We've worked around and seen that there have been a couple of places that discriminates on the classical and that just was a strange reaction which is, yeah, good. It's sort of weird but I guess it makes total sense when you really think about how it's operating. That's ruby for Rez? Yes, the one with the guy in the hat. Yeah, I think I have the hat which I'm really jealous of. And he's updating that, by the way. Working on it for 1.9 in case you're interested. Any more questions? Yeah, I have genetically weak joints. Anyone else? Okay, yeah. What other kind of benchmark can you talk about? Alias method chain is Satan. Alias method chain is Satan. And that's really about it. You're going to have to benchmark your usage. When it comes to performance and this sort of stuff, you're kind of killing it off anyhow because you're doing a lot of weird dynamic stuff and so you shouldn't look for ruby performance but the difference between instance eval and the singleton injection is pretty significant. Outside of that I don't really know as long as you stay within the eval family of methods the performance is going to be pretty flat and once you get outside of that and you start talking to singleton classes then the performance is going to be fairly flat and depending on what you're doing one may actually be better than the other but that's really all. You just kind of have to evaluate your special case and then work from there. Yeah. When you use extend on instance to see add behavior to that particular instance are you creating any meta class for every single object that you do that on? When you're going to use extend and include all that I don't think you are. Are you agreeing? Yeah. Okay I agree with that. So I should probably worry about like code generally. Yeah I think you'll have extra problems. So if you're doing 10,000 of them it won't matter that it may not be a good way to go but if you're doing it once or twice and when the architecture can't take those out then you should be okay.