So we're turning to our next main topic, the next place we can improve. And this gets you a lot of code reuse. A lot of code reuse. A lot of time saving. This is the use of generics. So where have we seen generics? And I've just sort of stole the dictionary definition for generics. Relating to or characteristic of a whole group or class, meaning general. Being or having a nonproprietary name, such as generic drugs. So that's probably common usage. We've all heard the term generic drugs. Frequently we go to the doctor. He'll say oh well you should just pay a lot less and here's the generic. Having no particular distinction. So that's what generics in the general vocabulary means. Generics in C++ means programming using templates. And the critical reason person behind generic programming, especially generic programming and use in the C++ community. Strongly influenced by Alex Stepanov, and Alex is a very remarkable person. He was originally trained as a logician. And if you think about logic, logic tries to do things that are the most general possible, it likes the the most general rules. And if you've ever looked at in your background in computer science or in mathematics at something like first order predicate calculus, which is a very common tool by both mathematical logicians and some computational theorists. You will see statements that say, for all x there exists a y, such that the following is true. Canonically, if you, try to go back to the Greeks, you'll hear a little tautologies like, all men are mortal. Socrates is a man. What can you infer? You can always infer that Socrates is mortal. So somebody studying these very, sort of, grand notations that could be applicable to anything. Was wondering why in a programming language like a Fortran, in the early days, or an ALGOL, or a Pascal, or an Ada, then a C, why were you always re-writing code that was almost the same except it's sort of like a recipe? You would have a recipe and you could have the recipe for chicken, but you could also do exactly the same kind of cooking on beef or duck, so why not just say this is a recipe for boiled meat. And then just whatever that particular main ingredient was, you have that one recipe and now you can use it for, again, lots of people fry fish and they're not so worried about frying fish, whether it's trout or bass. They just know well, you fry fish, and if its this thick, then you have to fry it for so long and if it's that thick, you fry it for less. And if you cook it, you want to put a little lime or lemon juice on it. So everything except for what the main ingredients are stays the same recipe and that just makes that recipe more generically applicable. That's where generic comes in. So Stepanoff was looking for mechanisms that allowed you to code generically. Now, historically, you could do generic coding in many of these languages, especially languages like The AI language Lisp. Lisp was, in some ways, a typeless language, and so it was the responsibility of the coder to know that they were manipulating things properly and so that they wouldn't get anything wrong in terms of type. They could write code that could act on anything. List had this very fancy data structure. It was a linked list built into it. Then you could do a lot of processing, storing things in those linked lists. And so it was very powerful and very concise. It was especially useful in the AI community, starting in the 60s, when it was invented by John McCarthy. So people who used it really wanted advantages of it in these high-performance languages like C. But the problem is that C required typing information. So you have an inefficiency problem. The way you get genericity in a language like Lisp is you sacrifice some amount of low level efficiency. So that was the tug that was going on in Stepenhoff's mind. How can he keep the the universality of a generic recipe and still make it official? Because most people, especially in the non research community, the business community need efficiency. Professor McCarthy used to say oh I'm not going to worry about efficiency I'll just wait a few years and the machines are going to be half as expensive and ten times as fast. And at some level that seems to be right, but whatever you're doing the next generation wants to do something ten times larger. So there's nothing like enough machine speed. It's never that way. It's always something more you want to do. And you can always Over stress your machine with something bigger. So, Stepanov concedes of using what was called templates to combine genericity with efficiency. So here's a very simple example. And we're going back to our swap. We're gonna see why this is such a powerful concept. We have the new keyword, template. Along with that keyword, we use angle brackets a keyword called class, and then an identifier. And conventionally at least when we talk pedagogically about templates we'll typically use something like T, or if we have more arguments we might use something like T1 and T2. And it is by convention something we capitalize. It doesn't have to be but that's capital as a convention there because it alerts us to the fact that this is what I call a meta variable. It's gonna be substituted for The substitution is gonna be with an actual type. Such as int. And we look at the code body and it looks the same as what we wrote in those earlier swaps, inline void swap. And here, we would've said int, int. And here, we would've said int, everything else was the same. So basically, for very little effort, that's this extra line of code, we have what's now a universal swap routine. So here's a prescription, here's how we write these generic routines. You take a normal function, so what I wanna to have you do in programming a and trying this out is first take a function you already know that works. And you know it works for whatever you think is a canonical type that you need. For example, you wanna sum something. Maybe you wanna sum an array of integers. Well, you also might want some an array of shorts or an array of doubles. So you take that specific type, the one you're comfortable with, write it out. And then, what you do is you change it in a very minimal way. Once you see that that function runs you add this template class d and substitute T wherever the type is a meta variable. Now, it will be the responsibility of the compiler to do the proper substitution. So let's see how main changes once we have templates. So we had overloading already and now we're having this new feature, generosity templates and I'm gonna show it with three different types in fact one of the types itself is going to involve a template. So C++, being object oriented and generic allows us to do coding that wasn't available in C. And one of the things we can do in C++ is typically in a library, and indeed, this would be, we would include the library sharp, include [BLANK AUDIO] standard library for complex numbers. So in this example, I'm going to swap integers, I'm gonna swap doubles, and I'm gonna swap that complex numbers, and the complex numbers themselves are a template. And their argument to a template is type double. And why is that? Because there could be other numerical basis for complex numbers. Think of a complex number as a real and imaginary part, that's normally what it is. And I'm really not gonna expect you to go revisit high school algebra or college calculus, but as some of you may remember, you use this little i notation for an imaginary number. And some of you said, oh, I'm not gonna deal with mathematics anymore once I saw that, but it's just for purposes of the example. It just shows how powerful C++ is, that it naturally adds complex arithmetic. And indeed there are languages in which complex arithmetic is basic, modern Fortran. Because it's so heavily used in scientific computing. While the original Fortran didn't have complex numbers as a basic type. Later, standard Fortran and a complex numbers are the basic type. But C as a systems implementation language never had any reason, raison d'etre, a purpose at complex numbers. But numerical scientists, once they saw the ability to add types, new domains, jumped on C++ as a powerful language and added lots of new numerical packages with their underlying domains and their underlying types. So again, it makes perfect sense to swap things, and what's swap? Well, the compiler says, well, I have a definition, a template definition to swap. So these are two integer types, so the compiler writes out this code replacing T. T is replaced by [BLANK AUDIO] nth. And then, the code for that type is compiled. So every time the compiler sees a signature that matches up with the meta variable T. It goes and writes the code for that meta variable and compiles it. So one thing to keep in mind is you might get what's called code blow. You might get a whole bunch of routines for as many times as you need to write code for swap. But you're only doing that because you need it anyway. So this is automating what, otherwise, would be your work. And it's automating your work in a very powerful way. In a way that, hopefully is going to lead to far fewer errors, as well. So again, we have cout properly overloaded and here's our double and the same thing's going to happen. Swap is gonna be re-written with T becoming double. Compiler's gonna do that. And here, same thing, but T is gonna become complex. And cout, this operator, also knows because the type safety and the semantics that were put in the library how to properly write out complex numbers, as well. So we get that benefit immediately once we understand how to use C++ templates, how to use C++ iO, and the fact is we get it in a meaningful type safe way, so that really makes all of this more convenient and more powerful. The compiler uses the template to write code appropriate to each set of parameters. The parameters are int and the compile code becomes swap int, int. The same thing would happen to the other two signatures. Each distinct signature is going to be mapped into a template. Now, what if you needed swap for a signature for which the template code wouldn't work? Let's say you needed to augment something or you were doing a swap of two strains. And for whatever reason, that wouldn't work because you needed something that would use, in effect, a string copy. And not just a kind of assignment. You can specialize and have a specific function for that swap. The specific non-template function takes precedence. So if the compiler, that just is ordinary overloading. So you can use ordinary overloading specific instances of signatures along with generic instances. Okay, here's a quick exercise if you understand all these ideas. Show you how powerful it is. Take what you know about summing and numbers using a C array. Try and write that code for example for answer double, debug it in C++, and then change it to a template and make sure that it all runs. Okay, so take a break. So here is the generic version of writing a routine that can sum any kind of array. Array name is data, and in this case we use as our variable for the generic summable. We're not using t, which is very common. And we're using summable because, as with any kind of identifier, it provides documentation. And it's telling us. That z type that we replace summable with has to allow for this operation. This operation must work. What could it mean if that operation doesn't work? Well, if that operation is not defined with a particular type, let's say that's fancy type of string and you did not define a plus equals operator overloaded on that string. Then what is going to happen when the substitution of the code, for that type occurs, you will get an error. Now it should be a syntax error because the error will be that it detects that it has no available operation. That's the best kind of error. The unfortunate kind of thing is what if it's a plus equals that isn't the intended arithmetic use of summation. Then it's going to work and then you're gonna get something at run time. That's what you gotta be afraid of with templates. They can be overly general and if the code makes sense, something will run and this is a reminder. Use summable here to remind you that the replacement types must have this arithmetic idea of summation. So templates are very powerful templates, rather generic that generosity doesn't necessarily mean that every possible type under the sun can use it. It means that the types that you should use it for should be meaningful in terms of the code you're writing. Some things are going to be near universal. The notion of swapping two things, that's probably gonna be near universal. But the notion of adding things means that things have to be solvable. So again, if you wanna go back to your analogy of whatever your basic recipe book is. Yes certain recipes can use arbitrary fish in frying them, but then you wouldn't want to use the same recipe on lettuce. Some other ingredient where that kind of ingredient would be damaged by the recipe. Would lead to something that was unexpected.