Today we will consider together un important block of this programming course: Object-oriented programming or OOP. OOP is a programming paradigm or a certain style of programming that is used in several programming languages besides C++ and will give a certain number of useful proprieties to your programs in terms of maintenance and modularity. At this stage of the course, you should know the basic fundamental aspects of programming. For example, you know how to express treatments using control structures, such as conditional loops. You also know how to structure data using arrays for example, and, most importantly, you know how to modularize your programs using the central notion of functions. These basic tools allow you to code in a a certain style of programming called procedural or imperative programming. This paradigm has the singularity that data and functions appear separately in a program Of course, the two interact, the functions work on the data, which influence in turn the execution of functions. But the two entities appear separately. For example, as we will see in a few minutes, in a concrete example, processes can be represented by functions. Data and functions can be linked by the passing of arguments. Data are manipulated via distinct entities, such as variables. One of the fundamental particularities of OOP is the possibility to bundle together functions and data into one same unit. Let's consider a concrete example. Imagine that we would like to write a simple C++ program that calculates the area of a rectangle. The rectangle is defined by its width and height. And so I want to calculate the surface. In procedural programming, I would likely proceed in this manner: I start by declaring a variable "largeur" (TN: "largeur" means "width") that represents the width of the rectangle, and that I would initialize at a certain value. I would do the same for the height. Next, the area would be calculated by passing the width and height as parameters to a function "surface" (TN: "surface" means "area") that would do the appropriate calculation. So we can see clearly in this example, that in such a program, the data and the functions appear separated. The variables allow me to modelize and stock the data that will be needed. And the data is processed with functions. The data and the functions are not directly linked. In this case they are only linked by the passing of arguments. So one important objection that we could make, concerning this kind of program, is the lack of a semantic link between the two entities. For example, the semantic link between the width and height. The fact that we are manipulating the with and height of a rectangle is hard to determine. For example, imagine that I am not francophone. So for me, the names "largeur" and "hauteur" do not tell me anything. And so it is hard for me to see that the two names are linked to the same concept : a rectangle. The semantic link that connects the data in this case, is not clear. It's the same for linking the data and the functions that go together. Imagine that you are a bit careless when you choose the identifiers. And that, for example, you call this function "produit" (TN: "produit" means "product"). And that for the arguments, you give them even less explicit names. As a result, it is difficult for for anyone else who reads the code to see that, in fact, we are calculating the area of a rectangle. However, the link does exist conceptually. In this case you are indeed manipulating the width and height of a rectangle. And it is indeed the area of a rectangle that you are calculating. So the fact of consolidating into one unit, a rectangle, the characteristics of the rectangle, such as its width and height , as well as the functions associated with it, will allow me to establish an explicit link between these different entities, and result in a much more structured comprehensible program This one of the fundamental aspects of OOP. What you should know is that OOP enables a set of new functionalities, globally giving more robustness, modularity, and readability to your programs. All this allows for a better maintainability and robustness with regard to modifying the program. If one day your program needs to be reused, we would not want to have to rewrite the whole code for example because of errors in the manipulation of data. Indeed, today most applications are never developed from zero, but consist of adding onto or maintaining existing code. And it is important to be able to do this at the lowest cost. We will see that the fundamental proprieties of OOP, that is, more robustness, modularity, and readability go exactly in this direction. OOP offers, in fact, four principal concepts: encapsulation, abstraction, inheritance, and polymorphism that allow for better organisation of programs in regards to robustness, readability, modularity, and maintainability, as I mentioned before. These central concepts are not exclusive to one programming language, but are central concepts of object- oriented languages in general. In this episode, we will consider defining encapsulation and abstraction. We will examine in the next episodes, the fundamental notions of inheritance and polymorphism. Let's start with the concept of encapsulation. Encapsulation is consolidating into one unit the data and the functions that that work on the data. Typically, as in the example of the rectangle, we will regroup into one unique entity, the width and height that characterize the virtual rectangle and the function that calculates its area. In jargon, we will speak of the data as member variables, or data members and the functions as methods (a.k.a. "member functions"). So in OOP, we will be able to define new data types, with, as we will see later on, the concept of classes, These data types can be used to work with data whose types are more abstract, such as the type rectangle. These data will be objects that will cohabit and interact in the program. An object-oriented program will typically work with objects that are characterized by their members: their member variables and methods. Let's examine now the concept of abstraction. Let's say I want to write a program that manipulates several rectangles instead of just one. In a procedural approach, I would typically have to declare as many widths and heights as I have rectangles. Which I do here for the first rectangle. And I would have to do exactly the same thing for the second rectangle. This is rather tedious! If I would like to now calculate the area of these two rectangles, I would have to call the function "surface" and provide, as parameters, the width and the height of each of the rectangles I call the function "surface" ("surface" means "area") passing each time the correct arguments. So you have to be careful, as this can be a source of error. Imagine for example, that I enter the arguments wrongly. If instead of passing as argument for the first call of "surface" "hauteur1", I enter "hauteur2", ("hauteur" means "height") My data aren't coherent, I am not working with the same rectangle anymore. The encapsulation process results in that I manipulate higher-level data, the notion of rectangle, to which I associate a generic description. In our case, any rectangle can be described by its width and height which can be linked to a same calculation of the area. As a result, I can work with the more abstract notion of a rectangle, instead of working at an intimate scale on the representation of rectangles, which allows us to concentrate the essential aspects and hide the details. Encapsulation allows you to consolidate into one same entity, the data, such as the width and height, and the functions, such as the calculation of the area. It is the tool that allows me having a more abstract vision of the data that I manipulate. As a result, I will be able to work with more abstract entities, a first rectangle, and a second rectangle, both of them are of type Rectangle. And I will invoke calculations of area on these rectangles. We will see that in object-oriented, I anticipate a little, I calculate here the area of the first rectangle. Later on we will see all this in more detail. As a result, my program will focus on the important elements. Therefore I am no longer preoccupied with the fact that a rectangle has a width and a height, but I can concentrate on the essential aspects: the fact of working with a rectangle, and calculating the area of this rectangle. So when I use a rectangle, I can only see what we call in object-oriented jargon, its user interface. That is to say, the functions that can be used to manipulate the rectangle, like in our case, the calculation of the area. Let us compare this with an everyday situation. When you drive your car, you normally only need to know the user interface. You need to know the steering wheel, the throttle, the brake pedal, but you never need to know how the motor was built. To drive your car, you only need to know the user interface. This applies to OOP as well. To use a new type of object, a new class, you only need to know the user interface, that is provided by the programmer of the class. The rest is internal implementation details that you do not need to know. So you can look at the object from 2 perspectives: from an external level, which is useful for the programmer-user, which uses the notion of rectangle. From now in a program the type Rectangle exists. I can declare variables of type Rectangle, initialize them appropriately. Next, the elements which interests me as a programmer-user, are the useful functions that come with the class: the calculation of area. So this external view is the perspective that interests the programmer-user, the programmer who uses the type Rectangle. The second level is the internal level. The programmer of the new type, the Rectangle type, had to deal with all the details of implementation. That is, that a rectangle has a length and width. He had to define explicitly how the area is calculated. This constitutes the implementation at an internal level, which not necessarily useful to the user who manipulates the rectangle. So in object-oriented programming, we do not only have the possibility to regroup into one same entity the data and functions, but we can also define levels of visibility. The person who programs the new type Rectangle, specifically a class Rectangle, will be able to say : " This implementation will not be accessible to external users." and "This is a function that we want to provide for the external user and therefore will be accessible to this user." Everything accessible to the user and, therefore, visible constitutes what is called the user interface of the class of the type in question. Here, in our class Rectangle, for the new type Rectangle we have defined as user interface the calculation of the surface. The rest constitutes the implementation details that are not accessible to the programmer who uses the type rectangle. And we have here an important key to achieving a more robust program when faced with the difficulties of changes made to the program. Usually, when you change car even if the motor technology is different, the interface is more or less the same. You will still be able to drive, even if the internal details of implementation of your car have changed. So you only see your car as an abstract object. You only see that which you use to drive, namely, the steering wheel, the throttle, the brake peddle. In summary, encapsulation, is consolidating into one same entity the data and functions that characterize it. And it is also concealing the implementation details. The user interface that we define using the encapsulation tool, is what allows me to end up with an abstraction, or a abstract vision of the objects. As an external user, only see them as objects that I can manipulate through the user interface. So concretely the class programmer will decide on the existence of a new type, and will have to address the implementation details. He will have to decide what is visible to the outside world, what can and cannot be used. The class user, on his side, uses the new data type. But he will have to use it through the interface. That is to say, the visible methods in most cases. He will not have access to the internal details. The user interface is typically, that which will enable a link to be established between the program developer and the user. And in a very specific way this interface will be able to be completely described by the signatures of the methods available to the user. So one of the principal advantages of OOP is the better visibility and coherence of the program. You have here two programs that do roughly the same task, calculating the area of a rectangle with a width of 3 and a height of 4. We are anticipating on the next episodes. Namely that we can initialize the width and height of a rectangle with this syntax. But it is more to give you an idea of what the program will be in terms of readability. If we compare the two approaches, we realize that here we are working with very low-level data. Here we are working with a rectangle, which is much more informative, regarding the purpose of the program. By reading this program, we know right away that we are working with a rectangle. Here the link between the data and the functions is only through the passing of arguments. Which is indirect. Whereas here, the link is more explicit. We invoke the calculation of area on a given rectangle. Moreover, because in OOP, we can only manipulate an object through methods of the user interface. Which gives a framework for utilization that is much more rigorous. For example here, as we saw earlier, nothing obligates me in this approach, to have coherent values, for the width and height, the width and height of the same rectangle. Here, this error is not possible, because we are manipulating a precise rectangle and thus the associated values are necessarily coherent. In addition, because the user is constrained to use the interface to manipulate the object, he is not concerned by modifications made to the internal implementations. As mentioned earlier, if we decide to modelize a rectangle not as an object with 2 member variables of type double, "hauteur" and "largeur", but rather as an object were the relevant data is stored in an array with two elements, the dimensions of the rectangle. So, if the program developer of the class Rectangle, did his job well, and adapted consequently the method calculating the area. The person who uses the area calculation will not be effected. We see in this small example the advantage of separating the internal level from the external level. This results in a more rigorous framework for using the program. And any modification to the internal structure cannot be noticed externally. So one of the fundamental rules, that we saw already in the introduction, the member variables, because decisions need to be taken as to their modelling, as well as technical decisions, and implementation decisions, are considered implementation details systematically in all good object-oriented programs. To summarize, when we define a new object type with a class, we will need to define the member variables characteristic to the class as well as its own specific methods, and we will have to define concretely, what is visible : the user interface, and what is not : the implementation details. Therefore once we have decided what we have to hide, we end up with the representation of the object for the external user that is essentially the user interface. So the external user's view will only be an abstract vision that is materialized in the user interface. The only thing I see of the rectangle is its calculation of area. And if I want to follow the rules of object-oriented programming, I will consider that the member variables are also implementation details. So the interface will be limited to a number of selected methods. The external user's vision of the object will be restricted to this user interface. What to remember from today's episode: abstraction results in what is called a class, which allows me to define a category of objects. A class will define a new type in a program. I now have the type Rectangle that I can manipulate in a program. I can declare variables of this type, which are actual realizations of this type. So the declaration of a variable of this type, is what is called in object-oriented jargon, an object. It is generally manipulated with a variable. Note that the term instance is also used to designate an object. To summarize and illustrate these remarks the person who writes the class Rectangle conceptually creates a new type. He will do this of course by writing a program that contains the code of the class Rectangle. The user of this class will use the new type, by declaring variables of type Rectangle that will only come into real existence at the execution of the program. So the moment the new objects of this type are created, we will be able to start working with these objects in the program. And the user will work with specific realizations of objects of class Rectangle. We've come to the end of this presentation of two fundamental aspects of object-oriented programming : encapsulation and abstraction. You will, in the next episodes, start to put in practice these concepts in C++.