 Welcome to the penultimate time slot of the conference. How's everybody doing? I'm pleased to say I'm finally over my altitude sickness, so I should be able to cope with this today. And I'm not sick in bed with 104 fever, which is great because the last time I was supposed to speak at Ruby Conf in Denver, that's what happened. So, praise be. Okay, so, welcome everybody, we're getting going. This is thinking in objects, so who am I? I am Josh Susser, I'm from San Francisco. I do the startup thing there. I'm CTO of a very small startup called Cognitive Health Innovations. We do mental health applications. I'm also on this podcast called Ruby Rogues. Who listens to Ruby Rogues here? Okay, who listens regularly? Who listens religiously? Who listens atheistically? Yeah, okay, great. I'm also an organizer of Golden Gate Ruby Conference. Yeah, okay, who's been to Golden Gate? Who's been to Goga Rooko? Oh, cool, great. So, I've been doing Ruby about seven years, and I've been doing object-oriented programming probably longer than some of you have been alive. I was doing small talk and OOP before it was cool, so that makes me an object hipster. Hold your heckling until the end of the talk, please. So, let's see. So, thinking in objects. This is me thinking about programming in objects, and you can tell I'm thinking because I'm wearing the thinking cap. You may not have a fabulous thinking cap, so I'm here to tell you how you can think in objects better, and write better Ruby programs, and be happier. So, I was very lucky to get to work with Alan Kay for a while, and Alan Kay, he's the guy who invented the term object-oriented programming. He was the creator of the small talk programming language, and he invented the whole concept of the personal computer. He called it the Dynabook. So, smart guy, and he's often quoted as saying something he actually said, which is that perspective is worth 80 IQ points. Now, 80 points of IQ is a big difference. It's like moron to genius. I mean, really. So, let's look at an example. So, don't shout it out, but raise your hand if you recognize what's on the next slide, and you're only gonna have a couple seconds. Okay, now who recognizes it? So, same thing, just a difference in perspective. There we go. This talk is about the conceptual foundation of object-oriented programming. I wanna give you a vocabulary for thinking about OOP so that you can write better code and be happier while you're doing it. This isn't a how-to talk. There's not gonna be a lot of how to do stuff, but there will be plenty of definitions. So, let's get on with the definitions. So, there's a lot of different kinds of object-oriented programming languages. If there were only one kind, there would only be one language, right? But they have, even though they have a lot of differences, they have a lot of things in common, otherwise they wouldn't be OOP languages. So, I'm gonna go over what those things are, and then we'll get into them. So, objects are things that have identity, behavior, and state. And then once you have objects, you get an object-oriented programming language by objects with encapsulation, polymorphism, and inheritance. So, that's basically my talk. Are there any questions? Okay, okay. I have a little more time to fill, so we'll continue on. Right, so, the punchline is, it's all about messages. When Alan Kay and the Smalltalk team at the Learning Research Group were putting together Smalltalk, they wanted to put together something that let them build computers that worked the way cells in your body worked. And cells in your body, cells are actually very powerful computational entities. What goes on in a cell is very difficult for us to simulate computationally. And the way cells interact, a cell, one cell in my finger, can't tell what's going on inside another cell, and it can't make it do something. The way they interact is, one cell will send a chemical message to the other cell, and then that cell receives the message and does something in response that it knows how to do. And when all goes well, you have a happy life. The object-oriented programming is built so that we can have computer software that operates the same way, which is really the only way that they could think of how to build really large, sophisticated, complicated programs that worked. But we're not talking about Smalltalk, we're talking about Ruby, which is something people have to remind me now and then. So, what about Ruby? Okay, who's seen a slide like this before? I have a picture like this before. This is like something that's the night of drunken hell from a grad student. Who puts these things together? This is the history of the lineage of programming languages and how they all interact. It's really hard to see because it's so small to fit everything on there, but in the pink circle over there is Ruby. And if you look really close, you can see that Ruby comes from Python. And Sather and Eiffel, and there's like Smalltalk way back in there. But, so, you know, I think the only thing these charts all have in common is they're all wrong. Okay, so I flew out here on Wednesday. I usually hate flying. I used to love it when I was a kid, but then the seats got smaller as I got bigger. And so now I kind of dread flying, but I got a really nice treat on the flight out here because I got the best person in the world sitting next to me on the flight. So I got the opportunity to show a couple of my slides to Matt's and got his comment on it, and he said, well, yeah, I got the def keyword from Python. But there's a couple of things for Eiffel and things like that. But really, he agreed with the slide when you next, which is the real lineage of Ruby. And so Ruby is like Smalltalk and Lisp got together and have a love child, and then went off to work and hired Pearl to be the nanny to raise it. So you have object-oriented programming, functional programming, and system scripting, and they all fit together beautifully in this really rich, flexible language. It gives you a lot of expressiveness, a lot of power, flexibility, but it can also lead to a lot of confusion and complications as programming styles collide. So OOP is a different kind of programming style from procedural, functional, etc. I've seen a lot of code that was nominally Ruby, but was actually Java or C or PHP. I mean, okay, who's seen that? Who's written that? Okay, thank you. Okay, so that's enough intro. Onward for definitions. The... So this is what I showed before. Objects are identity, behavior, and states. So let's start drilling into those things. Now, identity is the quality of existential uniqueness. Just because two things have the same value doesn't mean they're the same thing. I have a very good friend who's a twin and he is not his brother. Okay, so I'm gonna try a little analogy here. Who here knows what the Internet is? Okay, who here is a web programmer? Okay, good number of people. When you open your browser and you take a look at a web page like GitHub, there's some communication that happens between your computer and the GitHub server. The way that those things find each other to talk to each other is they use the domain name system to look up their addresses. So we have... We can look up the address for github.com and that comes back as a 32-bit number. We have a dotted quad notation here and that's a unique address for that server. There's no other server anywhere on the planet that has that same address so that means it has a unique identity. Now, we're gonna ignore things like firewalls and load balancers and reverse caching proxies because they don't really matter for the point I'm trying to make here. There's a lot of stuff in object-oriented programming as well, so skipping right along. So we have this unique address. We have the same kind of thing in Ruby. In Ruby, we have an object. Say we have a string foo and we can ask that object for its object ID, which gives us back a unique number that uniquely identifies that object. We can have another string foo and we ask it for its object ID and it's a different number. In Ruby, those numbers have to be different because those numbers represent the addresses in memory. So it's like a pointer in C. So they're always gonna be different. So we have two strings. They have the same value. They're spelled the same. Everything about them is the same. S, double equals T. But if you use equal question mark, that compares the identity of the objects and they're different. So we can say we have S and T and we shovel D onto the end of S to get food. T is still foo. So that's about it for identity. What about behavior? We have a string, we can ask it for its methods. Methods are the behaviors that the object knows how to do. So we can ask foo for its methods and we can see it can compare itself and tell how long it is and reverse itself in a number of other things. And you can create your own behaviors by defining new methods. So here we have a numeric type and we're telling it how to figure out if it's even or if it's odd. Okay, so, you know, we've now covered identity and behavior. And, you know, so that's where we're at. But we haven't built an object yet, but what we have is something that's still pretty interesting. We have things that I'm gonna call uniques here. These are different from singletons. These are things that do not have any internal state. There's nothing inside them, they're atoms. You can't cut, you can't chop them down in any smaller pieces, but they still have, you know, they're still interesting things and they have some distinct properties. So, and we deal with those things every day when we program in Ruby. So we have nil and true and false and use those all the time. We also have symbols that have spellings which make them different and they're certainly not singletons because there's many different instances of class symbol. But once you have a symbol, you never look inside it, the way that it's spelled never matters. It's just its identity that's the interesting thing about it. You can also create your own uniques. Okay, so who got to see Ben Ornstein's talk the other day about refactoring? That was a great talk. If you haven't seen it, you should go watch the video. So Ben showed the null object pattern to say, okay, here's how you create an object that represents somebody using the system who isn't logged in. And he created a whole class around that. So you only need one of these things and you're never going to have, you aren't going to have like 800 of these unique objects representing the same person, right? Or different people because they all behave the same. They're not logged in. They can only do one thing. So here's how you create one of those things without having to define a new class. You just say, I'm going to make an instance of object. There's no instance variables in it. It can't really do much of anything. So I'll start putting some methods on it and you can use the, you know, define a method on guest and you just give it a name. So it doesn't have to look in an instance variable to find out what its name is because it's always going to be the same. So we have an object that just because it has a unique identity is interesting and can do a lot for you. Okay. But it would be really hard to write programs that did useful things if all we had was uniques. So we need some state. State is the data that's contained within an object that lets it fulfill what it has to do to do the behaviors. So data is always in service of behavior. So here we have, we have foo, we shovel a D under the end and then we can ask how long it is so the object has to maintain some data for whatever its content so when you ask it how long it is, it knows. But objects, you know, like cells are like black boxes. You can't look inside it. So even though state exists from the outside, it looks just the same as behavior. Another way to look at that is we call that uniform access. Okay. So we have a person class and we want to ask it for its name. We have a, we can create that as an accessor and just say, okay, we have a first name. That's equivalent to defining a method with an instance variable in it that returns that first name value. But what if we aren't storing the names as a first name and a last name? Some people have middle names, suffixes, prefixes, whatever. What if we store it just as a full name? And the way we get back the first name is by splitting off the first word. If we have different classes of users, they can store their names in different ways and as long as they return them when you ask for a first name, you're good. The one way of, so uniform access means that asking for data looks just like invoking an operation on the object. Something that doesn't do this is JavaScript. JavaScript does not have uniform access. If you ask for the value of a property, it looks different from calling an accessor function. The first line is a property. The second line is a function. That means that if you want to change how names are stored, you have to go and hit every call site that accesses that property and turn it into a call in a function. That's the single thing that I hate most about this. Back to our analogy about talking over the internet, talking to a web server. If we make a get request on index, we don't know if Nginx is just returning an HTML file that's stored on disk or if there's a Rails application where an action and a controller runs and renders an ERB template and returns the HTML and all we know is that we send a get request and we get back a response with some HTML in the body. The name for this property is encapsulation and I've already said pretty much everything I need to say about it, so here's a picture of a Q-daughter. Our next property is polymorphism. In Ruby, we call that duck typing because if it looks like a duck and quacks like a duck, it'll probably cook up nicely in an orange sauce. The other way that I like to think about this is protocols. Everybody works with protocols if you do web programming. You have TCP that lets you send packets over the internet. You have HTTP that lets browsers talk to web servers. A protocol is just a set of rules for entities to communicate with each other. Another way to think of that is it's an API and objects that have compatible APIs can be substituted for each other. That's the essence of polymorphism. I think that's a pretty easy concept to grasp so I'm not going to dwell on it too much. Let's review for a moment where we're at. We have objects and we've covered encapsulation and polymorphism. That gives us what is called an object-based language. I didn't make up the term, but I like it and I think it expresses something pretty interesting. The secret sauce to an object-based language is dynamic binding or late binding and what that means is that the code that executes when you invoke an operation on an object is determined at runtime, not at compile time. This is what lets us write extensible frameworks like Rails because the code in Rails that calls into your application was written long before you ever wrote the code in your application. There's no way that it could know about your code at runtime or at compile time. Moving up from an object-based language to get to object-oriented, we get inheritance. One more thing about object-based languages. There are a fair number of object-based languages out there. We tend not to program in them for general purpose programming because they're not very fun to program in for general case stuff. I think they tend to get used for things like simulation and other special purpose applications. They're also great for what we do because they're not as efficient because you don't have inheritance. Inheritance is great because it makes you much more efficient in writing code. You get to share code and that's what inheritance is basically about. We all know about dry, right? Don't repeat yourself, DRY. As opposed to wet for right every time. I haven't talked about classes much here, but classes are a way that different instances can share their implementation. We have a bunch of user objects. They all share the code through a construct called a class. Classes can share their implementations by saying, okay, I have a super class and then I want something that's a little more specialized than that, so it'll be just like that, but I'll add some differences. I think everyone's probably familiar with that concept, but there are two types of inheritance to think about. One is inheritance of implementation and the other is inheritance of type. Given that Ruby is dynamically typed, inheritance of type doesn't really help us all that much. If you're working in a language like C++ or Java where you have to worry about a static type system, type inheritance becomes much more important. But the point of type inheritance is largely to make the compiler happy so that your code can be better performant. It can have better performance. There's a lot that compilers can do using the information and type systems to make the code run fast. But Ruby approaches things differently, so type inheritance isn't as useful for us. The thing that I want to stress about inheritance is that deep inheritance hierarchies are dangerous. You should try and avoid them. Sarah May said this morning that good code has few dependencies and she showed a few examples of that, including the law of Demeter and how that works. The thing to keep in mind with inheritance is that if you have a deep inheritance hierarchy your subclass is dependent not only on your immediate superclass, but all of your ancestry because any one of those things that changes, any of your ancestors that changes can directly affect you. So you're coupled to all of your superclasses all the way up the line. So it's best to avoid that. And you want to use... I prefer to use composition. So let me take a slight detour here and I want to talk about delegation. So how many people have heard the term delegation? And how many people are confused about what it means? Okay, so delegation gets used to mean two different things depending on which camp you're in or what language you work in usually. Most people who work in Ruby use delegation to mean something that happens in composition. So rather than inheriting from an array you create a new class that contains an array within it and then it composes itself with the array and can take on some behavior of the array by using the array within it. There's a great library in Ruby called Forwardable that makes that really easy to do. Rails has some built-in stuff for doing that within Active Record Models as well. The other type of delegation is used with people who talk about prototypical object languages. JavaScript is one of these languages so is self and in those cases delegation actually means inheritance. So in 1987 at UPSLA there was a really great paper presented by Lynn Andrea Stein called Delegation is Inheritance and she proved mathematically that prototypes and delegation was exactly the same as classes and inheritance and settled a war that had been brewing in the object oriented world for years. And then the next year a paper came out by a gang of people called Treaty of Orlando that made some really interesting and basically covered the whole landscape of different kinds of object languages and what their properties were and if you're nerding out on object languages that's a great paper to read. But that's not the kind of delegation that we usually talk about in Ruby but I just wanted to clarify that. So we've gone through we have objects encapsulation polymorphism and inheritance. But as I said the punchline is it's all about messages. If you can think about objects interacting by sending messages that's when things start to get interesting. So I'm going to show you a bit about how this works and make some recommendations. So there's a mistake that gets made by pretty much everyone who uses Ruby including people on the Ruby core team. And that's that when you invoke an operation on an object they call it calling a method which is wrong. So the real way to think about that is you're sending a message. Why aren't you calling a method? Well, if you're doing delegation when you invoke an operation on an object the real thing you're doing might not even be in that object. It might be in a different object that it's delegating the behavior to. Or even more nasty there might not be a method there at all you might have a method missing handler that figures out what to do when it gets that call on it. So the best way to think about that is that you're sending a message. So however there is actually a way in Ruby that you can call a method directly. I do not recommend this but I will show you how it's done. We have a yeah laugh Eric. So we have a person class and person has a name and then we have an employee subclass and when you print out the employee directory you want to know not just what their name is but their title so the name gets reported as name comma job title. But when you send that person that employee a letter you probably don't want to put you know, joshcesser comma cto on the front of the envelope so you want to address it to just the bare name which means you want to get the name as answered by the person class. So here you can if you look in that recipient name method the first thing we do is we pull the method out of the person class bind it to the recipient object and then we can call it and that's how you call a method in Ruby but don't ever do it or James Edward Gray the second will come to your house and hurt you. So let's all take the pledge from now on when you invoke an operation on an object we call it sending a message thank you very much. The next thing is use objects. Ruby is an object oriented language so use the objects. There's an amazingly rich set of core objects and fundamental data types in Ruby and that's part of what makes Ruby great to use but how does it go? A difference in quantity eventually becomes a difference in quality is the kind of thing that you can get away with doing it a little bit but when it starts to dominate your program design you're not doing object oriented programming anymore. I've seen programs written in Ruby that worked by passing around hashes and one of the keys of the hash was type and that type was a name for the kind of hash it was and each method that received that hash would do a case statement switching on that type and running a different piece of code so they basically reimplemented polymorphism that ran several orders of magnitude slower than the way the Ruby VM knows how to do it. Did people see Koichi's talk where he talked about optimizing the virtual machine internals and method dispatch? You see how much effort VM implementers put into optimizing these operations. You are not going to do better than that so let the VM do it for you. We have these data types. We have blocks and lamb dubs. We have arrays. We have symbols. There's a lot of really cool stuff that's built into Ruby and you can build programs out of those things exclusively but they will not be object oriented. You want to use objects. My friend Cory Haynes said Reification unites behavior with data and he uses the term behavior attractors. When you draw a circle around all of your data and behavior it's really easy to know where to put more. It goes inside the circle. That example I talked about with the hashes and the type keys the behavior in the program for how to interact with those data types was scattered all over the program so if you change something about that data structure you had to go find all of the code throughout the entire system and look and see if that would be affected. That's one of the primary advantages of object-oriented programming is everything is contained within the cell membrane. You know where it is. You know what you have to touch. Here's a few different variations of how you can do something in Ruby. In ActiveRecord we have validations. You have a person and they might have a phone number and you want to make sure that they do have a phone number so you can say validates presence of phone. I made the name short so they would fit on the slide here. Ordinarily I'm more wordy in my code. But maybe the user could have more than one phone. You want to make sure that they have either a home phone or a cell phone so you can use a block to do that. That's pretty easy. But maybe there's like a whole bunch of different ways that they could have a phone. They could have an emergency contact person who has a phone number and you probably don't want to shove all of that logic into a block right there in one line so you create a method and then you use the validate has a phone method to do that for you. But then you say, okay well I don't just have users I have companies that have phone numbers so I want to extract that code from that class and put it in its own class so I now have a has a phone object that does that validation for me. There's this whole progression of how you can scale from using very simple procedural type stuff into using more object-oriented patterns that will help you and make your life easier. So you don't have to go crazy and use a hammer everywhere but you want to make sure you don't get stuck using a screwdriver all the time instead as well. Well, I'll talk about a strained metaphor. Okay, moving right along. Polymorphism. Polymorphism is probably the thing I like most about object-oriented languages. It's it just, it provides a lot of flexibility and it's really how we think about stuff in the world. It's just, we don't interact with everything as if it's the same thing, right? Different things are different. So, as I said before, method lookup is fast. You know, Koichi's talk showed that they put a lot of effort into optimizing these things. You should rely on polymorphism because not only is it going to make things faster, it's also going to help you organize your code a lot better. That's the thing that lets you put everything within the, in that circle so it all is in the same class. So let me show you an example. Last week, Ryan Big, you know, hand, big round of applause for Ryan Big. He's done a lot of stuff for like documenting Ruby and writing some good code. He's a smart guy and he knows Ruby but he got himself in trouble. So he tweeted last week, oh my god, I can't do it with this code. I'm like, and he tweeted a gist to something and I looked and I said, man, that person needs to be taught a lesson. He's like, yeah, it was me. So I took a look at it and I saw what I could do. So let's take a look at what happened here. So this is the code that he wrote. And the only thing wrong with this code is that it's not object oriented. This is procedural code. And so I did a little highlighting here so we can see a little more what's going on here. Can people actually see the code? Okay. So let me talk through it. But there's three levels of conditional nesting here. And that's like, you know, it smells really bad. The first thing that you check is you know, is there a product? And then, okay, do we have an admin and are we looking for deleted records? But there's definitely some cleanup that you can do here. I took a look at this for like two minutes and it became pretty clear what was going on. If you look in the first half of the method, you know, between if product and else, the blue else, all of the messages there are being sent to the product. And if there is no product, you're talking to the variant class. And then within each of those cases, there's very similar structures where you're saying, okay, if I'm an admin and looking for deleted, then I get to see all of the things, otherwise I just see the stuff that isn't deleted. So I looked at it, I said, okay, I can do a couple refactorings there. And this is what I ended up with. So I wanted to make it polymorphic, so it was the same message being sent to different classes of things. So I just inserted the aliases for those messages into the variant class. And then within the scope method, I collapsed that first conditional. If you go back here and look, we got if product, else something else. I said, okay, great, we're either using product or variant because in the second clause all the messages went to variant. And then there's only two cases left. You either want to show the deleted things or you don't. So this is the kind of thing that you can do when you learn how to think correctly in objects. And you're using polymorphism, you're using classes. We have objects. Identity, behavior, and state. We have object-oriented programming. Objects, encapsulation, polymorphism, inheritance. And the real secret sauce is messages. So one more thing. My Ruby Rogues podcast is a finalist for the podcast awards. And voting is going on now. It's going to be going on through November 15th. You can vote once a day, each of you. So vote early, vote often. Thank you very much.