 The object-oriented paradigm can be quite neatly summed up as simply privileging data over action. That is, in contrast to procedural programming, where we approach our problem by decomposing it into a series of actions, aka functions, in object-oriented programming, we approach a problem by trying first to decompose it into a bunch of data types. Now, of course, in either paradigm, you end up defining in your code both actions and data types, so the difference really hinges upon which do we think about first, code, or data. In procedural programming, we think in terms of functions, and then as a secondary matter, we consider the actual data which those functions act upon. In object-oriented programming, we simply reverse that, we come up with data types first, and then we have to decide what operations we need associated with those data types. This inversion in our approach is really quite simple if subtle, but in practice there's a bit more to object-oriented programming, including a few principles which we'll discuss. The interesting question, though, is what's the point? Does object-oriented programming really have virtues that procedural programming does not? This is something we'll also discuss along the way. Many popular programming languages today are considered object-oriented languages because they include features which assist or even encourage the programmer to program in an object-oriented style. Take, for example, these six popular current languages, three of which are statically typed, Java, C-sharp, and C++, and three of which are dynamically typed, JavaScript, Python, and Ruby. Now, we've already covered JavaScript, and you may be wondering, what about JavaScript as object-oriented? Well, JavaScript is actually kind of an oddball in that it uses an unusual mechanism called prototypical inheritance, which is what we saw in the language when objects got linked together by use of the new operator. We covered how that feature works and what exactly it does, but we didn't discuss why it exists in the language. What's the point? That's something you should have an ocean of by the time we finished this unit. Again, though, JavaScript is really kind of an oddball, where JavaScript uses prototypical inheritance, most other object-oriented languages use what's called class-based inheritance. What is a class? Well, a class is simply a definition of a data type, and each class, each data type is defined by the members which make it up. Members come in two basic kinds, fields and methods. Fields are the data members. They are the data which actually makes up the type. For example, if I create a class to represent a cat, well, a cat could be made up of a bunch of different pieces of data, like, say, a string for its name or a number for its age or remaining lives, or perhaps other fields to represent things like its weight and color and so forth. So, when we say a class defines a data type, we're defining a compound data type, a data type composed of a bunch of other pieces of data. And those pieces of data, those fields, they can be any kind of data that exists in the language. So, they can be the built-in types like strings and numbers, but they can also be any type defined by a class. So, for example, if I create a class to represent a car, well, a car might be represented as composed of a bunch of pieces, pieces which themselves may be instances of other classes, like, say, an engine class or a steering wheel class. And note that term instance. When we create a class, the class itself is just a blueprint for creating actual pieces of data. The actual pieces of data themselves are called instances, or more generically and more confusingly, often called objects, hence the term object-oriented programming. The other kind of member of a class is called a method. A method basically is a function associated with that class. As we'll discuss, the idea is that these methods are the operations for acting upon the data, the fields of the class. A very important thing to understand is that when we instantiate a class, that is, when we produce an instance from a class, that instance, that object in memory, gets its own fields separate from the fields of all other instances of the same class. So, say, if a class represented a cat, has a field representing the cat's number of lives, well, then each cat instance we produce has its own number of lives field, because every cat has its own number of lives. My cat has seven lives left, yours has five. With methods, however, is a different story. Both of our cats meow because that's just a thing that all cats do, so the class cat has a meow method. However, this doesn't mean that the instances produced from that class, the cat instances, need their own copy of the meow method. There's just one piece of code associated with both of those objects. There's just one copy of the method in memory. When we invoke this method, which cat instance does the meowing gets determined by which cat instance is passed to the method. So, again, keep in mind when we instantiate a class, that instance object has its own copy of the fields, but not its own copy of the methods. The first principle of object-oriented programming is called encapsulation. The idea of encapsulation is simply that the fields of an object and instance should only be read or written by methods of that instance's class. So, say, in the cat class, the principle of encapsulation says that the number of lives field of a cat object should only be read and written by methods of the cat class, not by methods of any other class or by any other code. So, when we're writing code outside of the cat class, outside the methods of that class, the only way we're supposed to be interacting with the fields of any cat object is by invoking methods of the cat class, and then it is the methods themselves which may directly read and write the fields of cat. Say that this here represents some instance of a class with three fields and four methods. If we want to read or write one of these fields, we should not do so directly from outside the object. Only the methods of the class should be directly reading and writing these fields from outside the class. Externally, we only interact with the fields indirectly by invoking the methods. The thinking here is that when you create a class, the methods you give that class encapsulate, they encompass, all of the knowledge of what is meant to be done with the data that makes up that data type. The hope is that if we strictly follow this principle, our code will end up neatly and cleanly modularized, thus allowing us to easily make changes to add features and to fix bugs. When you fail to adhere to this principle of encapsulation, data in your code easily ends up getting read and written from all different places in code. The result is what we call spaghetti code, code which is extremely difficult to understand and therefore very difficult to fix and modify. When adhering to the principle of encapsulation, we commonly make a distinction between public and private members of a class. The public members of a class, we say, are visible anywhere, meaning that it's okay to access them from outside their own class. The private members, in contrast, are the members which are only meant to be accessed by methods of the same class. When you follow the principle of encapsulation strictly, all fields should be kept private. Methods, on the other hand, may either be private or public. The methods only used by the class itself, you would keep private, but those methods which are used to interact with the class from outside the class, you, of course, would make public. Some object-oriented languages are more strict about enforcing the principle of encapsulation than others. The static languages actually prevent private members from being read or written outside their class while the dynamic languages typically do not. The second important principle of object-oriented programming is called inheritance. The idea of inheritance is simply that some data types, some classes, may overlap, such that one data type has all the same stuff found in another. When our programming language has a mechanism for inheritance, this allows us to formalize these relationships. So, for example, say we have three classes, one called Animal with the members A, B, and C, one called Mammal with the members D and E, and another Cat with the members F and G. For our purposes here, it doesn't matter which of these members of the classes are fields in which are methods. In any case, if we link these classes together by inheritance, such that Cat inherits from Mammal and Mammal inherits from Animal, well, what that will mean is that the Mammal class will automatically inherit all of the members of the Animal class, and in turn, the Cat class will inherit all of the members of the Mammal class, all of the members which Mammal itself inherited from Animal. So, here you can see that the Cat class has the member E as defined in Mammal, and also has the member B as defined in Animal. So, even though when we wrote the Cat class, we only specified that it has members F and G, because we specified that Cat inherits from Mammal and Mammal inherits from Animal, then Cat has the members A, B, C, and D. This is automatic inheritance. In which didn't have any kind of automatic inheritance mechanism, then to get the same effect, we would have to explicitly define the members A, B, and C in all three classes, and the members D and E in both Mammal and Cat. Doing this would not only be bothersome, but potentially error-prone, if we want to make sure that the definitions across the classes stay exactly the same. With an inheritance mechanism, we don't have to worry about accidentally forgetting to include a member in Cat and giving it the wrong definition. Now, an important thing to get straight here is the terminology for the relationships between classes. Here in this example, we would say that Mammal and Cat are subtypes of Animal, and Cat is a subtype of Mammal. And conversely, we would say that Animal is a supertype of Mammal and Cat, and Mammal is a supertype of Cat. Alternatively, instead of saying subtype, we could say descendant, and instead of saying supertype, we would say Ancestor. So, for example, Animal here is an ancestor of Cat, and Cat is a descendant of Animal. And then, a bit confusingly, we also have the terms parent and child. A parent is a direct immediate ancestor, and a child is a direct immediate descendant. So here, for example, Animal is a parent of Mammal, and Mammal is a child of Animal, but Animal is not a parent of Cat, nor Cat, a child of Animal, because the inheritance in that case is not direct, only indirect through Mammal. The real question now is, what's so great about inheritance? Why have some classes be subtypes of others? Well, the most obvious use for inheritance is when we're modeling real-world objects, as we presumably are doing here with these classes Animal, Mammal, and Cat. In the real world, you do have things which effectively form this kind of hierarchy, where a Cat is a kind of Mammal, and a Mammal is a kind of Animal. So when we create classes to represent those three things, it makes sense that we put them in a hierarchy of inheritance. If a Cat truly is a type of Mammal, just a more specific kind of Mammal, then it will need all the same features that the Mammal class has, as well as features specific to Cats. Like, for example, all Mammals eat and sleep, so it makes sense that the Mammal class might have methods called eat and sleep for eating and sleeping. But Cats also do some things which only Cats do, not all Mammals, like Meow and Purr. So if you had a Meow method, you would put that in the Cat class, not the Mammal class. Now, in practice, the vast majority of classes programmers make don't really model real-world objects. The classes which programmers make tend to represent much more abstract sorts of things. When dealing with abstract entities, it's often not so obvious when one type is truly a subtype of another or not. However, when you can successfully identify such relationships and create a proper inheritance relationship in your code, you may end up saving yourself from duplicating functionality in one class that already exists in another. In fact, it's fairly common when working with an existing program that a new feature you might add can be successfully implemented by simply taking an existing class in your code and extending it, that is producing a subtype of that class. When this works well, it allows you to focus on just writing the code for the new functionality, not having to duplicate already existing stuff. It's very common, though, for learners to get the misimpression that they should be using inheritance all over the place. This is not the case. You need to think before you use inheritance. The simple rule you should keep in mind when thinking about using inheritance is to ask yourself, is the relationship between these two classes really an is a relationship or a has a relationship? In a proper inheritance relationship, instances of the child class are considered more specific versions of the parent class. So, for example, a cat is a kind of mammal. That's an is a relationship, so it's a proper use of inheritance. In other cases where you might be tempted to use inheritance, the true relationship is not an inheritance relationship, but a composition relationship. For example, a car is composed of many parts, including the steering wheel. So if we have a car class and a steering wheel class, then it makes sense that the car class has a steering wheel field. That's a has a relationship, because it calls for composition, not inheritance. It would not make sense to have the steering wheel class inherit from the car class, because a steering wheel is not a kind of car. And it wouldn't make sense the other way around either, because a car is not a kind of steering wheel. If we were going to extend the car class, we would do so with something like Toyota or DeLorean or sedan. Something which is a car, a specific kind of car. So when thinking about using inheritance, just be sure to ask yourself, is this an is a relationship or a has a relationship? In some languages with inheritance, a single class may inherit from more than one class, such that say here, Kate would grab all the members of both the Ted class and the Milton class. Many other languages though, like say Java and C sharp, don't allow this. They only allow single inheritance, such that each class can only inherit from one other class. This choice between allowing multiple inheritance or not is mainly a trade-off between simplicity and flexibility. Single inheritance is generally much less confusing, and it means that the language doesn't have to have any sorts of rules to deal with situations like say, Ted and Milton both having a member named X, raising the question of how to handle the name collision that results, because Kate inherits from both Ted and Milton. Which X does Kate inherit, the one from Ted or the one from Milton? If our language has multiple inheritance, it has to have rules for covering such corner cases. In single inheritance languages, we just don't have to think about such cases. On the other hand, multiple inheritance may sometimes come unuseful, as it allows us to take multiple existing classes and sort of mix them together, combining the features of multiple classes into one. What's definitely not allowed in any language though, is circular inheritance, wherein a class ends up indirectly inheriting from itself. Like say, here Kate inherits from Ted, and Ted inherits from Jack, and Jack from Milton, and then Milton inherits back from Kate. No languages allow this, because it simply doesn't make any sense. It's not clear what it should mean really. In some object-oriented languages, every class is required to inherit from at least one other class, and by default that class is a special class which is built into the language. So as we see in our diagram here, every class except object itself is inheriting from some other class. So the object class effectively sits at the top of the hierarchy, such that any class you create is going to be an ancestor of object. The point of this is that the built-in object class is meant to represent just a generic object of any kind, and so it makes sense that any classes you create should be some types thereof, so anything you create is, of course, going to be a kind of object. You'll see this kind of inheritance tree first in Python and then later in Java. To override an object-oriented programming means to redefine an inherited method. So here, for example, we have this chain of inheritance from object to Jack to Ted, Lisa, Kate, and then down to Mike. Well, if the Jack class is defined to have a method named foo, then all of its descendants will be the same. However, if in the Lisa class we define a method also named foo, then Lisa will have that foo instead of the one inherited from Jack. And in fact, Kate and Mike will inherit the foo of Lisa, not the foo of Jack. The utility of this is that, yes, a subtype does all the same things as its ancestors, but a subtype may need to do that thing in its own specific way. Like, say, in a real-world situation of mammal and all mammals eat. Well, we might choose to override the method eat in the cat class because a cat eats in its own particular way, specific to cats. The purpose of overriding is probably a bit clearer if we look at how methods get invoked. In most object-oriented languages, we invoke methods with the syntax of first an expression that returns an object, then dot, and then the name of the method followed by, in parentheses, a list of arguments separated with commas, just like a regular function called. The reason for this syntax is to fold. First, methods generally live in the namespace of their class, so we can't just refer to them directly by name, we need to look for that name in a particular class. So what typically happens in this syntax is that the type of the object tells the language in which class to look for that method. The other reason for this syntax is that if we invoke a method, we somehow need to specify the instance of the class on which we are invoking the method. In effect, the instance the object here gets passed in somehow as an argument to the method. You may recall in JavaScript there's this special trickery whereby the instance gets passed to the special word this. In other languages there are different mechanisms but with the same idea. The object, the instance, somehow has to get passed into the method while also serving the role of identifying the type, the class, in which the method is found. Note that method calls are then naturally polymorphic. Here for example when we call x.foo which method foo we're calling which operation depends upon the type of x. Or looking at the inheritance tree from our overwrite example, if the x expression is a Lisa object or Kate object or Mike object, this will invoke the foo method defined in the Lisa class. If however the x expression returns an object of type Ted or type Jack then this will invoke the foo method defined in the Jack class. The actual operation, the actual method being invoked is changing based upon the types of the arguments. In this case the type of the instance. The fields and methods we've discussed so far are known as instance members because they are particular to each instance of the class. For every instance field of the class each instance has its own copy. When invoking instance methods the instance is passed to the method. In contrast what are called class members belong to the class itself not any instance. A class field represents just a single piece of data and when invoked a class method has no instance passed to it. While in most languages class members may be accessed via instances of the class as if they were instance members they may just as well be accessed via the class itself. And in fact I generally prefer always accessing them in this way as it's less misleading. In truth class fields and class methods are really not proper object-oriented fields and methods. A class field is in effect really just a global variable that happens to live inside the namespace of a class and a class method is really just a plain old procedural function that also happens to live inside the namespace of a class. I would even go so far as to say that if you use a lot of class fields and class methods in your code that code isn't really object-oriented at all it's just procedural programming in disguise. So why are class members allowed at all? Well in some languages such as Java your code is meant to consist entirely of just classes. So if Java didn't allow for class fields and class methods or as they call them in Java static fields and static methods then you would have no way of writing just a plain old function in Java or just having a plain old global variable. So in a way class fields and class methods in Java are just compensation for Java's odd design decision of requiring all code to live in classes. On the other hand we do have languages like Python where you can have just plain functions and plain global variables but Python also has class fields and class methods. In this case a class of which to use is really just a matter of style. Sometimes for organizational purposes it makes sense to group things into classes even if they're really just plain functions and global variables. Just be very clear class fields and class methods aka static fields and static methods are not true members of a class in a proper object-oriented sense. When we create the instances of a class very commonly we want to do some kind of setup work. For this purpose we have constructors. A constructor is simply a method which is run when we instantiate a class. So for example, given a cat class when we instantiate a cat object the cat constructor method is automatically invoked with the new cat object passed as the instance and then that cat constructor does presumably whatever setup work is appropriate for a cat object. Now in many cases the constructor does nothing more significant than just giving the fields initial default values. In other cases though you might need constructors that do much more complex things like actually run some real code. What's appropriate is really entirely context dependent on what exactly your code does. Another important term in object-oriented programming is interface. The notion of an interface is that you may have two different types two different classes which though perhaps unrelated share a set of methods in common and we call that set of methods an interface because given any objects of classes which share that interface we can interact with those objects in the same way with the shared set of methods. Like say we have three classes a cat class a robot class and a fighter jet class though otherwise unrelated those three things are all things which both move and stop so they might all have a move method and a stop method. If these methods in all three classes take the same number and types of parameters and return the same types these methods effectively form a common interface. The way you tell a cat to move would be the same way you tell a fighter jet to move so we can invoke the move method on an object without concern for whether the object is either a cat or a fighter jet because it can equally well be either. The concept of an interface needn't be formalized in a dynamic language. In javascript for example I can invoke x.move on any object and whether the object x has an appropriate method of that name is only checked when the code is actually executed. However in a static language like java I must explicitly define an interface much like I must define a class and then I must specify which classes implement the interface that is which classes have all of the interfaces specified methods. So in java here I would have to define a move stop interface to have two methods move and stop then specify that the classes cat, robot fighter jet I'll implement this interface meaning they all have their own methods move and stop with the same arguments and return types. Only then could I write the code x.move in java where x could be an instance of any one of these three otherwise unrelated classes. So this is an area where dynamic languages are much more convenient in a dynamic language you simply invoke any method you want and whether the object actually has such a method is discovered at runtime if it turns out that no such method exists the language of course throws an exception. In contrast in a static language the compiler has to be assured that the object has such a method before the code even runs this prevents runtime errors but at the cost of more up front hassle. An abstract class is a class which is not meant to be instantiated. Instead an abstract class is just meant to serve as the ancestor for other classes. For example in your code you may have no need for any say mammal objects but you do have need for dog and cat objects so it makes sense to create an abstract class mammal from which you extend the dog and cat classes this way you can place the features common to both dog and cat in their shared ancestor even if that ancestor itself is not going to get instantiated. In some languages like Python there is no formal mechanism for creating abstract classes you just create a regular class and just never instantiated but in most static languages like Java you can define a class as abstract in which case the compiler will then give an error if you try to instantiate that class. The idea is that this helps enforce your intentions that a class not be instantiated it's by no means an essential feature but it can be slightly helpful especially when you're working with many other programmers one programmer declares a class abstract thereby ensuring that no one else will mistakenly instantiate it so now that we've looked at classes let's look once again at prototypical inheritance. If you recall in JavaScript we create just what JavaScript calls objects but JavaScript has a way a rather convoluted way whereby we can link objects together such that when we do a property search on one object the search follows the link to other objects until it finds the property of that name. By this mechanism you effectively can have an object which represents a class and any other object that links to it is effectively an instance of that class or alternatively an object which itself is a class and by virtue of the link acts as a child of the other object. So the weird thing in prototypical inheritance is that you don't have any formal notion of classes you just have a bunch of objects linked together and it's up to the programmer to treat certain objects like classes give them methods and fields and then produce instances which link back to the object. I'll reiterate this is really kind of a strange approach and in fact JavaScript's really the only language of any note that uses it every other major object oriented language has a formal class mechanism. Last thing once you get comfortable with the basic ideas of object oriented programming you'll probably want to read up on what are called design patterns. Design patterns in object oriented programming are pretty much what they sound like. They are common ways of organizing classes to solve recurring problems. The term design pattern was coined in the early 1980s with the release of this book design patterns, elements of reusable object oriented software. The book became very influential and the authors are now collectively known as the GOF the Gang of Four. If you do read the book you should understand that it's now quite old so you'll want to supplement it with some more up-to-date information on design patterns because in some of these areas people's thinking has changed a bit. So you also very much should keep in mind that the loose nature of dynamic languages make a lot of these design patterns unnecessary in those languages. In any case, even if you do work just in dynamic languages it's probably good to be well versed in at least the most common design patterns because they have certain names like Flywheel, Observer and Singleton which are at the very least useful as convenient shorthand when communicating with other programmers.