 Okay, so it's my pleasure to welcome Bjarna Strauss-Truth to Michigan. He needs no introduction. All of us have used C++ in one of our courses here. He's the designer, inventor of C++. I'm sure we'll give you some background to that. He is a member of National Academy of Engineering as well, which is a huge honor. Only very few selected people get elected to that. He started after his PhD at Cambridge, even doing Bell Labs, where he did his work on C++. He started out in distributed computing and then realized that he needed a language which was to get abstractions better than in C. And that's how C++ started. And now it's one of the most popular languages around. So I'm not going to say anything more and welcome. Okay. Thank you very much. Thank you. What is going on here? Because my computer is still showing the show. I mean, I didn't touch it. What does it need to do? Is there some sort of a timer or what was? No, it's not screwed in. Do we need to? I was a bit nervous about this talk because this is a brand new talk. I haven't timed it before. It's a bit long as new talks tend to be. And then I come and see the room is totally full and then I'm told I have 10 minutes less from my talk than I thought I had and then my screen disappears. Anyway, so I'm going to try and I'm going to try and speak a little bit faster than usual because I am way behind already. I mean, that may be the story of most of our lives but nevertheless, I'm going to try and speak fast. By C++ style, I mean, how do we recognize a good program when we see it? What is the guidelines for writing good code and why? That's what I'm going to talk about. And the inspiration is the blind man and the elephant. I find that when I enter a room, I'm often the only one who doesn't seem to know what C++ is. Everybody has a firm opinion. They've got hold of the tail or leg and they know everything about it. This is not the case. The point is how do we integrate all of this understanding knowledge language features into something that gives good programs? I mean, my view is this, there's an elephant and the idea being is the C++ is a language that allows you to write lightweight abstractions and program based on lightweight abstraction. Lightweight means cheap and time and space and basically what this is good for is for building things we can call software infrastructure and for applications that are resource constrained. A resource constrained application is something like running on a small gadget like a fuel injector or demanding a lot of performance like say a Google server farm. This is where C++ has strength and I'm going to try and explain what I mean by that and how that works out. I'm not going to talk specifically about C++11 that is a new C++ standard that was voted in this year. That's what 11 stands for. Because I want to talk about how you write programs using the whole thing. You don't write programs using just the latest features. Everything's been designed to fit into what there is so that you can write good code and C++ is not a layer cake sort of you. You first write some C code then you write some other code and eventually you write the modern code. You should start thinking how do I express the solution to my problem? How do I express it well? And I'm going to try and give you some rules about how to start out by that. If you really want the list of new features go to my FAQ and you can get the list of new things. Okay, what is good? Nothing's working today. So this is one of the ways people are seeing C++, the joke about the Swiss Army knife with all the knives out at the same time. Basically some people see C-style, some people write just C with a few classes. Some people are really keen on true object oriented virtual functions everywhere, class hierarchies everywhere and some other people don't like anything unless it's a template. The point is that this is like the elephant. You see one part of the beast and not the others. The idea is how do you combine all of this? Now I'm tethered over here. Another thing to remember is that the application domain for C++ is immense. It's used in just about every kind of application you can think of whether that's a good idea or not is beyond it, but just because you're part of the elephant suits you doesn't mean it suits everybody. So we have to take into account that there are different application things. Some people care only about getting things to the market first. How many bugs doesn't matter. Others, if they screw up, you have a windmill farm going haywire or plane crashing, you have different constraints. My interest drifts towards this end of the spectrum where you have performance critical, safety critical, stuff, but you can do whatever you like. What we want is all kinds of good things. Comprehensibility I think is the most important thing. If you can't understand it, well you can't maintain it and you probably didn't get it right in the first place. But from there you want modularity because you want to understand things from a local point of view since a modern system is too big for you to understand completely at all levels of abstraction anyway. We don't want resource leaks, we want threat safety because most modern systems are concurrent somewhere or other. Efficiency matters. If anybody tells you otherwise, I've got a bridge to sell you. Tell that to Google, it costs 50 million dollars to put in a new server farm. Tell that to somebody whose phone battery is burned out after half a day. And I want portability where it matters. You can't port all software, but it's nice if it can run on all the processors and operating systems you've got. So here's an overview of what I'm going to do. I'm going to show you an example that ought to scare you and then I'm going to show a whole bunch of alternatives and then sum up. Now, maybe you've seen code like this. I borrowed it from somebody. This is actually semi-real code. Somebody thought this was good enough to actually show to other people about how to write code. Now, you may think this is good code if so you should probably fail your programming course. But that's not the point. You can also find bugs in this while I'm talking. The point is this code down here is not just shorter. It's more general, it's correct. It works for a variety of data types, not just the characters. It is not a security hazard and it probably runs faster too. So we want to get from this view of what programming is to that view. Okay, this is example unfair. Well, somebody actually thought it was a good example to teach people from. So it's not totally unfair. And to quote said Beeplebrooks, I get weirder things than that in my breakfast cereal. The bigger the program, the more of this kind of horror you get. And the only good thing I could think about that code is that it's almost certainly crashes at first run. Somebody didn't test that at all. So again, is it unfair? I don't think so. I think the use of the programming language features, the style is the number one problem in delivered code. In code you can find in actual use and it's also the number one problem in teaching of C++, which far too often is simply teaching of some obscure details of syntax with little understanding of what it's for. So, okay, so here's something about interfaces. There's a lot of interfaces around that in code today. Increase speed, give it a double. Rectangle made out of four integers. I mean, what's a rectangle? Is it a point and another point? Is it a point or a height and a width? Or what is it? I don't know. I would like to have alternatives like this, top left point, bottom right point, top left point area. So I know what it is. Now, this one up here is interesting. You can encode any piece of information in a double. So what does that double mean? This is the Mars climate orbiter. It was about to go into orbit around Mars and it got an instruction, it was wrong. There was a unit failure. So on the one side of the interface, it was imperial measures and the other side, it was MKS system, SI units. The thing went about 150 kilometers off course. It crashed, it's $564 million down the drain. It's the life's work of about 200 good engineers down the drain and we didn't get the academic, the scientific results from that. It was because somebody had an interface like that. They just passed the value. No problem, no checking. So let's see how we can do this. The point is that we were all taught, I think, in high school how to avoid that problem. Calculate using units. Make sure that the unit is right before you bother doing any complicated calculation, right? It's easy. So here, we can have a speed meters per second, makes sense. Meters per second square is an acceleration. We can catch that. What we got here, we got an error. A non-unit thing divided by seconds. What's a unit divided by seconds? I don't know. And here's an acceleration. That actually makes sense. And you could build a language for that. People have. Doesn't times probably. It's a good master's project. The problem is nobody uses it because it's not integrated into some language that can do all the other things. So I'm just going to show you how to do this. Because I'd like to encourage you to have really rich interfaces in terms of the types it's expressed with. I don't want the plain doubles. I want double that that shows me a little bit how to use it. So I can build a little type system here. Here is a unit. It takes meters, kilograms, and seconds. It's a triple. That's a unit. And the value is the actual magnitude, the value, and a unit. And so, like I said, speed is a value which unit is 1 for meter, no kilograms, and divided by seconds. Acceleration, just divide by second squared. So I can write this. And we can now go about, wait a minute. My clicker doesn't work. OK, so that's fine. I can write this. It's C++11, but only due to the using speed thing there. But people never used it. And one of the reasons was that the library that can do this has been around for a decade. People didn't use it. You had to write things like that up there. The speed is the value for that unit and the value for that. This is obscure. It starts out being verbose and end obscure. So you need to get a notation that actually works it out. And this code actually provides literals of unit types. So you make a second is something that has that unit. Second squares have that unit. And we can say that this operator is operator little. It is if you see a literal with a suffix S, it makes it the value, takes it into a value of seconds. So given that code, you've seen it all now on the screen. This code is legal C++. So I've just worked from the requirements which came out of your physics textbook written 30 years ago or something. It's code. And so it's all compile time. You can do it runtime if you like. But if you put runtime, heavy stuff on a space probe, you need to send more memories. And that's expensive and heavy. And it doesn't fit in the launch system, things like that. So compile time only doesn't weigh anything. And there is no runtime overheads either. Doesn't cost in time. So it's easily done. But that's what you'd like. Keep interfaces strongly typed. Avoid very general interfaces. I worry when I see int or double. Because what does it mean? And int can encode just about anything. I would much rather see a speed than a double. And in object-oriented programming, I worry about object. There isn't such a thing as an object. It's an artifact that represents a lot of things. I can see matrices, dial buffers, threads, and things like that. I don't see any objects. That's an abstraction. And it's so wide that if you say I take an object, you really should be able to work on any object I give you. That's your interface. The alternative is you say you'll take an object. You take any object I give you. You look at the object that runtime says, no, I don't like it, which can be quite painful in terms of time, speed, logic. What do I do if it gets the wrong one? So that's good. Now let's look a little bit about things that occurs a lot in the kind of code I care about. It's resource management. Here we have a fairly naive program that has been written in many versions for the last 20 years. I open a file, I use the file, and I close the file. This is an error waiting to happen if it hasn't already happened. If you use exceptions in here and exit, you might not close the file. You don't need exceptions for that. If you write good old C, a return statement will do it fine. So what a long jump starting from down there and getting up. So this is a problem. It's been found in many real programs. So a lot of people say, well, yeah, exceptions. Let's put in a try block. And we get code like that. This was a nice piece of code we just wrote, right? Except that it's been blown up. So somebody thought it was a good idea to take the simple code, make it more complicated thereby removing the bugs. There's something fundamentally wrong with this idea. The number of bugs you have in your program tend to be proportional to the amount of code you've got and the complexity of the code you've got. Here we have got more code, and it's more complex. There's something wrong with this solution. And you can clean up the syntax a little bit, but it doesn't matter too much. What you really want to do is to say, well, the piece of code here does resource management. It grabs a limited resource, in this case a file handle, and it releases it at the end. If you grab too many file handles, you freeze your computer. It's bad as a memory leak, or possibly worse. OK, so let's say it's a resource, so let's acquire a resource and release it. And the model for that called RAII, Resource Acquisition and Initialization. You just make something that is a handle for the resource. There's the file handle there. When you make a file handle, you open the file, and if you can't, you make an error. And when you destroy the file handle, you close the file. So now the code becomes like this. Give me a handle to the file with that name for reading, and then use it. Whichever way we exit the scope, we now have it cleaned up. So here the code got simpler and safer, and simpler means easier to write. This is good stuff. And of course, you would want these things in libraries. And some libraries do use this technique they have for a decade in the C++ standard libraries, strings, vectors, maps, all the containers work this way. They grab memory, holds on to it, and release it when you leave the thing. Lux and streams and threads has exactly the same model now in C++ 11. You acquire your resource, you use it, and then they take care of itself. So here's a little thing. You have a mutex that protects some shared data. The way you deal with that is you grab the lock, you use the data, and when you leave the scope, the resource gets released. By the way, there's some measurements that says that this strategy tend to lower the time you retain a resource dramatically compared to other strategies, like doing it totally manually or letting a finalizer do it or garbage collection for memory. But garbage collection is only for memory. So this is the recommended style here. Basically, we do that when resources are scoped, but not all resources are scoped. What if I want to create something, give it to you, you give it to him, things like that? You have to do something else. But we want to use this when they're scoping. Otherwise, what you use is pointers or references, but that can leak. So what we use is smart pointers and references, resource handles. Here's sort of a little example as you find it in much beginner code. There's a guy who's proud of being a Java programmer, so he allocates a gadget using new, assigns it to a pointer, go down and write code, and what's going to happen here. Whatever is pointed to by that pointer is going to leak, because we left. Here, I throw an exception. Here, I return. This is bad, because we never get to this delete statement down here. This is bad code, whether you have exceptions or not. But if you're going to do this, if you want to hold on to this one, then you can use a shared pointer, which keeps a use count and deletes things when it's finished. So you get here, it deletes, get here, it deletes. Basically, shared pointer is a resource handle that holds a pointer. Fine. You could say, why a shared pointer? I'm not sharing with anybody. I'm just holding on to this object in such a way that it'll be properly cleaned up, whatever happens. So we have a simpler version also that's a unique pointer, which is simply a handle with a destructor to an object. If you manage to initialize this one, the destructor will be called, will freeze the object at the end. This is a very useful thing. It can also be used to pass out objects and things like that. Standard resource management kind of stuff. And by the way, of course, you shouldn't have used a free store element. Anyway, a local variable would have done very nicely, thank you. And it would have worked simpler, better, more efficient, less code, all the good kind of stuff. One of my rules in sort of modern C++ is no naked news. I mean, why would you have a new operator in your code? It belongs inside resource handles or in arguments to resource handles. Back there with the deletes, it's implementation stuff. You don't need to see news and deletes in your code. So basically, people say, what about resources? What about management and stuff? I don't actually leak. My programs don't leak very much anymore. And I don't spend much effort to make them not leak anymore, because I've used this stuff for years. It works. Same like I tend to use range checks to L containers, so I don't have overflows anymore. That's passed, so we'll do that. So basically, you address the point as a premature destruction in leaks. You have some choices. And basically, if you can build the acquire and release mechanism into the fundamental semantics of the objects you're using, then you are much better off. Think of lock, think of file handle and open, think of vectors and lists for their memories. All this resource management has disappeared into the semantics of what you're doing. So we have now sort of dealt with, if we get some objects and we want to release it, there's a problem that has bothered me and actually caused a lot of grief over the years, is how do you get a lot of information out of a function? It's very typical, you call a function to do something, and it makes a nice bundle of information to give to you, so how do we get it out? The classical example is a matrix. OK, we can take two matrices in, we can add them and once get the result out. Now, how do we get it result out? The first idea a lot of people have is we just make a new matrix inside and pass a pointer out. That looks ugly. You actually get a pointer to a matrix out, not a matrix, so you have to write this kind of stuff. It's unacceptable. And anyway, who does the delete? Inside here is a memory allocation. The memory retention is not automatic, is not structured, so somebody has to delete who. I don't know, I can't see it from that, and we can make it even worse. Most people's next good idea is that you return a reference. You take in references, why don't you return references? The answer is this looks right, but it isn't. That is a memory leak waiting to happen unless you start getting really clever. OK, let's try it for again. Let's pass, what am I doing here? I'm passing a place to put the result in. If you look a lot of C code where you want to do something, you just pass a reference in that you put the result in. Often a pointer here, I've used a reference. Now the syntax doesn't work anymore. We'll have to say that your math textbook wasn't quite right because you need calls with three arguments to add. First argument, second argument, and the result. That takes care of the memory management, but now I have to allocate it and such. I would say this is too ugly for words, but let's try something else. This is what I've been doing for a long time. You just take in the references because it's just const reference, just an optimization of getting information in and put a matrix out. Nice, Corby's semantic, right? You take the matrix, you give it out. Now, Corby can be expensive, and so we try to optimize that. There's some dirty hacks about putting a stack of return values or a circular buffer of return values. They can optimize that brittle hack, it doesn't work. What you really want is you want to move the matrix. Now, a lot of computing works on the notion of copy, right? You copy something, and now you have two copies, and if you didn't want the first copy, you throw it away. That's not the way we usually work with physical resources. Okay, I've got something in my right hand. I want it over there. Empty. Put it over here, right? That's the way it works all the time. If we don't actually copy. Copy is sort of computer speak. It's an implementation detail. So you want to implement the moving out by stealing the representation because we know it's just about to go away anyway. So let's see, here we have the idea. I write my matrix, I copy the stuff into this, and I return it, and here it gets the result. But what I want is the following to happen. I have R here, it points to all the elements I built. When I do the copy, I want that pointer to go over into REST, my target, and I want R to become nothing. I can hand code this, and I've been doing it for a decade, but it's complicated, not everybody does it. What you can do in C++11 is write a move constructor. There's move constructors and move assignments. They move, just like copy constructors and assignment copies. And the way you move, here's a typical move constructor. It takes an R value reference, that's funny notation there, but basically copy the representation, zero out the original representation. That does exactly that. So now I can move a 10,000 by 10,000 matrix out of the ad operation at the cost of two assignments of words, maybe three if you also store the dimension. But it's that kind of thing. And this is actually wired in to the new standard library. So you can now return a vector, cost six assignments, return a list, cost four assignments, independently of the number of elements. I mean I do things like create a vector of 100,000 elements and pass it out by value. It looks funny till you get used to it. This is a style talk, right? It's what can you do? It actually is the most efficient way of doing it. It's the simplest way of doing it. It just does what you're thinking about. Look here, right? I can teach it's a kindergartners. They all do it. Only one exception, arrays is the modern version of the old build-in arrays that doesn't forget its size and they really are a chunk of memory. And you can't move a chunk of memory, right? It's a physical resource. It doesn't move, it sits there right in the memory. So, but the containers do. So no naked pointers. Keep pointers inside functions and classes where they belong. Whatever you do, keep arrays out of interfaces. If you want to pass things around, pass containers around or references around, pointers and implementation level artifacts. Don't show them to your users. They don't need to. They don't want to hear about them anyway. If you consider unique pointer and shared pointer when you want to pass things around, you're most likely not going to leak and not going to be hit by exceptions or other error problems. And return objects by value. That takes care of a lot of the moving objects around inside a program. So now I'm going to show a little example that first was presented to me by John Bentley many, many years ago. This is, there's not a trick question here. It's genuine. So we have an exercise. Generate n random integers and insert them into a sequence in their proper order. So here, if I have five, one, four, two, I first put five in. One comes before five. Four comes in the middle. And two comes between one and four. That's fine. So you build a sequence up by putting in elements. Then you pull down the sequence again. You give it a sequence of positions and you pull out things. You pull out the one position two. Then you pull out the position one position two. Then position zero and finally the last one. So the thing here is, for which n is it better to use a vector, a contiguous sequence of elements than a list, a linked list of elements? Those are the two obvious ways of representing this sequence. And I'm not going to, I don't have time to do the nice socratic things of asking you and discussing things. But I'll just say, my guess was, I think the vectors will work best up to maybe 1,000. Bentley laughed and pointed out that all of his tests show 10,000. And let's see. This is what I got when I ran it last week. This is an 100,000th element. It looks the same down here. But look here. The list is going through the roof. There's just too many insertions and deletions for lists to work. Wait a minute. What did complexity theory say about that? And Vector is doing really nicely. And somebody said, oh, it's because he's doing all of these allocations and deallocations for the list nodes. Okay, I preallocated the whole thing. It's better. It's much better than the standard list. But it's still not good. What's happening here? Your mileage will vary. I've been doing this with my students. And I mean, there are some cases where Vector is only better up to about the 200,000. And the complexity theory says you should get as a topic advantage to list. But let me see. Now, first of all, there's dramatic difference in the amount of memory we're using. And the cost of storing an integer into a vector is one word. That's the word for the vector that the integer goes in. For a list, it is the integer plus the forward link plus the backward link plus the link to keep track of it in the free store. So we just increased our amount of memory by a factor of four, minimum. Use a 64-bit architecture, and it'll be six. I didn't have to know that. So that's a four-to-one advantage. What does it mean? It means you fall out of the cache very soon with a link list. Worse than that. A link list, of course, allocates in the free store. So when you're traversing a list, you're going, there, there, there, there, there, there, there. Modern cache architecture doesn't like that. What they really like is you to do this. That's what a vector does. So the fact that you stick an element down in a vector and you have to move 2,000 integers, one position to the left, it's not actually too bad. Modern machines are good at that. The fact that you have to traverse the list to find the insertion point, and then you can very cheaply put something in between two elements, doesn't matter. Machines doesn't like it. You run out of memory. And basically, I ran out of main memory before the list's advantage could come up. Complexity deals with asymptotic complexity. We never hit the asymptote. We hit swapping instead. So to understand a question like that, by the way, you have to know your complexity theory. You have to know your data structures. And you have to know your machine architecture. And you can also know your algorithms. There's extra credit for that. And I didn't even, I was trying to be fair, I didn't even use a binary search for the vector. That would be a low blow. But what I do here is don't store data unnecessarily. The same as the interfaces up there with the units on them. Don't use data if you don't have to. Keep the data compact. The machines really, they vary. These days, memory is relatively very, very slow. And all the optimizations we have wins if you don't have too much data, if you don't have data, and if you access memory in sort of a streaming fashion. Random access is a very misleading word because you pay the Earth for random access. Stream is much better. So by the way, just to be fair, let's not go there. I have to rush. There is the code. This is generic C++ code. It's an algorithm. You just find where you're going to insert it. Then you insert it. That's a lambda function. So find in the sequence where the integer is supposed to be an insert. And on the way, and the do insert is do it for all of them. That's the code. This is my argument that maybe you should think about algorithms. I'll get back to that point. But when I write this, the whole experiment complete with a timing code is ever so slight in comments. It's ever so slightly bigger than a page. And there's only one piece of code. This stuff works both for lists and for vectors. When students first do it, they write between two and five pages. I mean, don't they have anything else to do with their life? There's actually a reason for this kind of style issue to matter. Saves you a lot of time. So here's a compact layout. People have looked at this list example and says, well, this is artificial. Yeah, it's artificial. But this is equivalent to what you do for large data structures. Maybe I don't have a list of half a million elements. The people or my friends from Google and Amazon laugh and says, we don't either. They're too small. Now, what is much more likely in my code is that I have 100 lists of 1,000, which is exactly the same, or a million objects of, say, two or three words. And you have the same effect. Here you have a vector of four points. Very simple little thing. And in C and C++ it'll look something like that. Here are the values. Here are the interface that says where the values are stored. This is the resource handle. A vector in this case. And it's got four elements. So it's compact. If you count that, including the overhead of putting it on the free store, you find that it's 10, 11 words there. And if you really, really squeeze it, you can get it down to getting rid of that point on the free store. So you get down to a logical minimum. Now, if you go through object-oriented style, you have the reference to the vector. And then this one should point down here to the elements. And the elements are references to the point. And they go there. And if you count it, it's more than twice as much. So you can get effects like you saw with the vector of list just by having a couple of points. Now, performance doesn't matter if you only got a couple of points. Fine. But if performance matters, because you've got lots of elements, or you do a lot of things to them, compactness matters immensely. Also, I recommend generic code for a style of writing. Focus on algorithms and write generic code. Here's what I'm doing here. I'm finding something in a container. I thought I'd skip this slide. Sorry. Anyway, we find something in a container using an algorithm. I'm not going to go through this, because we are running out of time. But basically, it illustrates the point from before that algorithms is a really good thing for simplifying your code, not writing page-in-page of code and then having to debug it. Here, that just explains how you can compose code in the previous slide. Here, I used findif, which is standard. I used vectors and lists that are standard. I used a date that wasn't. I used some lambda functions to put it in place. And it all is composed rather nicely. Findif works for, that's findif, for container. It works for any kind of container with any kinds of elements, and we can provide predicates for selection based on it. It can do marvels to the compactness of your code. And I was doing things like that for the vector and list example. This gets me to this example here, which I actually borrowed out of a commercial product, which shall remain nameless, even though there's some good stuff here. The point is that on a screen, you want to drag an element into another position in our menu. So you take it from over there and stick it in there. And the original code for doing that for 25 lines of code, there was one loop, there was three left tests, and there was 14 function calls, and it was basically unreadable. Basically, the author of it was worried, oh yeah, and he has to do it differently for each operating system. So consider this having to be repeated with different details about 10 times. Is it correct? How do you know without testing this kind of thing is difficult? Is it maintainable? Well, since its author has trouble reading it, it probably isn't. The only hope for maintainability here is that it never needs to be changed. Because if nobody touches it, it'll probably stay all right. Is it usable elsewhere? No. Even from one operating system to another, it had to be changed. Now, here we have a professional. The author looked at it and didn't say, OK, Don, let's do something else. Anybody wants to help me look at this code? This is not good code. It may do the right thing. I'm sure I tested it, but I don't trust it. So what did I just say? You take something and stick it in the middle. OK, so what you do is you go and do a findf for the sequence so you find the spot that is where you want to stick it. And then you rotate. If it's over here, you rotate it in place, and here you rotate it in place. If you know the standard library, this becomes fairly simple. It's fairly comprehensible. If nothing else, the essence is these two statements. And it's comprehensible. If you're a domain expert, there's no problem with this. It's maintainable. Remember that the semantics of findf rotate and rotate are well-defined, specified mathematically. You can go and look them up. It's comprehensible. But it's a very special purpose. What is this coordinate there? And what is this vector? It's capitalized. It's not the standard one. So they said, well, looked at it a bit again, and said, you can generalize that, and came up with this one. This one actually comes from an observation that some operating systems allows you not just to take one thing and drag it over there, but to select. Click, click, click, click. What is it? Shift, click, click, click. And then drag them all into one place. So how do we do that? We want to partition it so that anything that doesn't meet the predicate goes first, and anything that does meet the predicate goes after. This one is called gather, and it's shipped in various popular open source libraries today. It works for other things, too. It works for all the cases where you make a selection and then put them in one place. You probably didn't know a stable partition. Personally, I can never remember what it is, because I use it only every second or third year. And so I have to look it up. But so what? The description is this much, and it's in the place where you can find it. The code here is de facto one statement. There's no loops. There's no conditions. And it's more general. It's faster, and it applies to any sequence. It's shipped on a variety of operating systems. So we have to get to a more algorithmic level of code. Because otherwise, maintainers or us being maintainers will end up looking at this 25 lines of messy code again and again and again. OK, so that's it. Consider large function suspect. Large function is something that doesn't fit on a small screen. It has a lot to do with the way we understand the world. We take something into a very short-term buffer called our memory. And then we chew on it. If there's a little bit too much information, I mean, the new modern screens are so that my old example of had to fit on the screen is not good enough. Because some screens are too big to use for functions. You want a small function. Anything bigger than this is suspect. This is ideal. And any control structure is basically suspect. If you write a loop, you can be falling off the end of it. If you write an if statement, you can reverse the condition. If you have a mixture of loop and conditions, you are in bigger trouble. If you have a couple of loop and a couple of conditions, you probably also got a bug. So we have to go more algorithmic. And this leads to the question, but can you afford it? There's a lot of people that think that low level equals efficiency. Remember my first ghastly example? A lot of people say, wow, it's efficient. It deals with characters. And it's written in C. It must be fast. So I did some experiments here. I was trying to write a loop here that just make a sum. Now, everybody will agree this is efficient. After all, this is just some syntactic sugar or the C4 loop. And it is efficient. You can't write it better. But the point is you can also do for each, for a sequence using a lambda to do the sum. Now, this will work for any sequence. This one doesn't work if it's a list. This one works if it's a list. So you can generalize and you can afford it. I timed it. You can't tell the difference. If you do this a few million times, it still comes out to the same microsecond. I just can't tell it. There's people who tell it's identical code, but that's not for all compilers. By the way, I tested on a couple of compilers and a couple of architectures. You can't tell the difference. By the way, you should, of course, accumulate for that. So it's built-in. But if you want to do it yourself, you can write these. And the point here is you could use anyone. You could have for every second that's the algorithm. Or this could be a tree traversal where this is the standard one goes depth first. You could write a breath first. It will all work. If you do it with a loop, it becomes very different. So one of my old examples I've done for a long time, I take sort and stream IO. This is standard C++. And I compare it to Q sort and STD IO. Now, everybody knows that because this is more general and cleaner and shorter, it must be slower. And I mean, as late as last week, I had somebody who absolutely refused to believe this was correct, even though I just ran it. OK, so what did I get? 0.7 for the sort, 9.2 for stream IO, 1.7 for the Q sort, and 4.4 for the STD IO. So they have an optimized stream IO very well. It's a partially old OO design. It has heavy weight, no cals in it, the functionality that very few people uses. And you don't see that way anyway. And maybe more effort gone into standard IO. But the sort, the one that was the point of it that sort of rearranges a lot of elements in a thing, it has better inlining, better type safety, and it runs 2 and 1 half times faster than the C version. Basic reason, C takes a pointer to a comparison function to do the comparison. Pointer is a poison to optimizes. Pointer indirect function calls a poison, so you can't do it. C is, by the way, getting better. It's only 2 and 1 half times as slow as C plus plus. But I don't think they'll actually get there. I think it's impossible. There's fundamental reasons why the higher level here works. And so don't lower the level without good reason. Low level gives you more code. That means more bugs, because however clever you are, if you write more code, you are likely to have more bugs. And it's much harder to understand and maintain inheritance. I keep hearing that C plus plus is object oriented. Yes, it supports object oriented thing. So what does that mean? It means that if your domain has hierarchies, like the graphical domain does tend to have hierarchies, you can use it. And you use, in particular, if there are the need for runtime selection among alternatives. But the point is you have to ask the question, where do you use inheritance? And the answer is, where the problem demands it. Not because it's cool or because you can't do without it or because somebody said that member functions are good for your health. So I'm not going to say anything more about inheritance. I probably should. But I assume you all know a lot about it, so therefore I can skip it. The other thing, type safe concurrency. We have had concurrency for years and C plus plus been non-standard. And it has tended to litter your code with macros and void star stars and other good stuff like that, which kills performance and makes bugs. So what we can do is we can write code like this. Say I have two functions here, a function f that takes a vector and produces a salt point wherever p points to, and the other one that returns a result. I strongly prefer this, but there's a lot of code out there that tries to deal with the problem I showed you with the move semantics. That is, you need to get a lot of information out of a function. How do you do it? They give an extra argument. Let's see how we do this concurrent in concurrent code. So I make a thread that says f is called by some vector on res. That's fine. So the thread will do that. And we can tag another thread, which will take g, get the result into res2. So this binds to res2. So it just calls it. So we can take these functions and just make threads to run them. Now, of course, threads are heavyweight beasties, so there's better be a lot of work here to be worthwhile threading. But I'm not addressing this question. I'm just saying, if you want something concurrently, how can you do it? And this is fairly simple. You have these functions. You would have written this if you had no concurrency, and you would have written that if you did not have concurrency. So the overhead of concurrency in terms of notation, you can see there, it's not actually too bad. Then you have to remember the joints to make sure that everybody finishes before you get to the end, and you can write out the results. This is sort of an intermediate style. It shows what you can do. It's fairly conventional. Just about every C++ library for concurrency has something like that. So let's improve it a bit. Here is the same two functions. And here, we are going to use async, which is a launcher, which says, I would like to run these asynchronously. And that function async says, does it make any sense to do it now? And maybe it launches a thread, or maybe it launches, just does it in the current thread, dependent on the load and things like that. So here, now it's the ugly version that has to be modified. So basically, I have to have a local variable. I have to dump the result in a local variable and then return it here. I return it into something called a REST. Type is carefully not specified here. It's auto. Auto is a new feature that basically says you get the type of your initializer. Makes a lot of sense. I implemented it first in 1983 and was forced to take it out of the language because of seeing compatibilities and because nobody could see what it was good for. It's been rather popular since. And now we've got it in C++ 11. By the way, a lot of features of C++ 11 are available shipped today in the Microsoft compilers, in the GNU compilers, in the C-Lang compilers. They've all got this one in particular. And they've all got the lambda as I've been showing. And the quality of the support for the concurrency stuff is also available. In other words, this is not a science fiction talk. You can run it today. It probably is on your computer already. Anyway, what was returned by async was futures. There are little handles that allow you to get the return value when you want it. So here we say, get the first result, get the second result, and write them out. So that works. So that is one way you can write concurrency. Now, if you wrote nice code in the first place like that, you would get nice code like that. The complicated version was the adaption of old style. I'm not sure I should have shown you that, but it shows that the old code are still good. So what have we got? I want you to practice type-rich programming with a good focus on interfaces. Remember, simple classes are cheap. Use lots of them. And avoid over-general interfaces. I mean, if of double, unless you are willing to give a result for every double there is, it's probably not a good idea. And if double has to be a particular kind of double, like a speed, you better introduce the type for the speed. Use compact data structures. The examples I showed you are synthetic, but they are mapped into real-world code. If you are dealing with performance critical things that could be big programs, it could be programs running on your cell phone, think about compactness. It's the first order of performance. Have a general strategy for error handling. I'm so fed up with reading programs that sets error codes and test error codes and invariably don't set them often enough and don't test them often enough. I like exceptions and have a strategy. This strategy integrates the notion of error handling and the notion of resource management. You can't separate the two anyway without getting into trouble. So this is actually important. If you look at the various programming languages, the integration of those two things is a source bot. Prefer algorithms. You really have to get used to writing more algorithms. Use type safe concurrency. Don't fiddle around with void stars and that kind of stuff. Build and use libraries. Start out with libraries. The C++ standard library is a good place to start if you don't have any reason to do otherwise. I mean, you might be writing flight control software, in which case you either have to have an adapted version or you have to have a library that doesn't use FreeStore because that's not allowed in flight controls. For good reasons, you really don't want the plane to do strange things while you're in it. OK. I got to the end of this. Questions? Looking at the high level abstraction, what about shifting to another language than C++ because maybe you're not doing infrastructure programming? Does that make sense? C++, especially the way I present it, is focused on low level and close to the hardware. On the other hand, if you looked at these examples, which language would you use that was higher level? Python? Python has a nice effect. Oh, type safety is an issue, right? Type safety is an issue. You use dock typing. It's really nice, like the templates I'm using. The point is that it's very hard to exhaust to testing. It's actually very hard to do testing. And you have overly general interfaces everywhere. Furthermore, you do run at a tenth of a speed. That means you use 10 times the battery life, or you use 10 times the number of server farms. So I wouldn't write everything in C++. If I was going to write a web service, I'll probably use Python or PHP or JavaScript or something like that. And that's fine. But that is to a very large extent because you want to save on programmer skills. You want to compensate for lack of understanding by using runtime. You want to compromise reliability because it doesn't matter too much and, of course, performance. So there's trade-offs. A lot of trade-offs have been made over the last decade or two, saying, well, the most precious commodity we have is human brain power. Let's shift everything away from the humans. Let's assume the programmer is a fairly stupid and very lazy. And what can we do for them? I think that's a stupid and insulting attitude. And you can afford it in some areas, like in little web apps that are not life or livelihood critical, but you can't afford it in the infrastructure. And so my argument, the one I stand by, is infrastructure. That's where this kind of argument comes in the strongest. And the more overhead you can afford, the more time to market becomes critical, the more the absence of qualified software developers becomes relevant, you go in the other directions. But this is crucial for the C++'s crucial domain and I think useful beyond that. But the answer is strictly true for the domain I'm most interested in. I think, yes, that is a big problem. I think a lot of the industry with the agreement of a lot of academia has decided the system development is a low-level skills. You need less training to develop web applications than to do the plumbing on my house. I don't think that's the right model. I think it's a model that'll kill us. I literally mean that. I've had a discussion with people. I made the statement, if our computerized systems collapse, most of us would starve. And says, you're being ridiculous. No. Somebody sets up a nuclear blast in the stratosphere and we are without computers. We can't deliver the food to the cities. We can't coordinate things. We'd starve. A massive lack of the computer infrastructure, we're back to the Dark Ages, except that they knew how to feed themselves in the Dark Ages in a good year. Without computers, we do not know how to do that. So I am quite worried, and I would like to push for professionalism, and I think that people who couldn't understand that code shouldn't be let near infrastructure. By all means, trying to become gasillionaires writing web apps, just like the other million people that are trying to do that. But don't get to the flight controls in the plane I'm on tomorrow. And I think in the education field, somehow we have to learn that educating possibly fewer students to be good software engineers, good software developers is more important than to keep people busy who writes bad code and can barely manage to write the ghastly example. I don't know quite how we are going to get there, because the pressure for the politicians is to produce more and worse students, faster and cheaper. And the industry love the idea that programmers are less skilled than mechanics, so they don't have to be paid as much as the plumber. I mean, there is the old joke about the plumber comes in, fixes something cheaply and writes out a bill, and the housewife says, but that's more than my husband gets and he's a lawyer? He says, yes madam, I was a lawyer before I figured out how to do plumbing. We need to raise the level of competence and the level of professionalism in the field and if we don't do it, we'll suffer. That's actually... The second you said was important. I don't move towards languages, that's not the way I think. I'm thinking more in lines of how do you round out features to better support programming styles. There's people that observes that something like Auto is called Let in the Functional Languages and they've been doing this for at least 15 years and well, I've been doing this since 83 so I didn't borrow it from it, it came naturally out of it but certainly if I hadn't known it that would have been something I would have borrowed from. The concurrency with Async was borrowed, the futures were first formalized in Multilisp a long time ago so you could say I borrowed it from there but I don't think there's a single language that you sort of could say that one is sort of getting it right and I'm going in that direction because I think as a matter of fact I think a lot of the languages today is going in the wrong direction. They are relying more on runtime resolution, they are relying more on sparse data structures, linked data structures, they are relying more on global things like garbage collectors as opposed to local things like scopes and I find that global things interfere with my ability to reason about my programs. I really think when you go to concurrency you must be able to think about the threat of code running on this processor without worrying too much about other threads and this is not true. A lot of times if I'm a task and you're a task and I give you a job to do I give you with you in the old style I give you a set of pointers and when you get to the data you access my data so what I do is scramble my cache so I'm starting to run slowly because you're using some data that I might have used but I'm not. That's not good. These things dissociated so I would do more copy and less passing by reference but the modern languages they use the free store all the time the heap, the dynamic storage, whatever you call it they use references for everything. This is the wrong way. They also go very much for very general interfaces they work for object but they don't actually work for object they allow the library implementers to write in terms of object and give a runtime error it doesn't document what I'm going to do to do this correctly so I worry about the trend in programming languages like that and then I borrow whenever I see an individual thing that makes code cleaner, safer, faster, more compact I borrow there and I'll take for any language that come and if you know my writings I do give credit I do give acknowledgement, I do give references and it is not very common in this field people forget that they don't invent everything themselves I don't want to move away from the model of declaration and definition I think of it in terms of declaration specify the interface and definitions specify the implementation and I want them yanked apart the analysis of code to be based on the declarations and if it hinders refactoring build a tool that will attach that will connect all declarations to a definition and work that way I would say you simply have primitive tools I actually was very happy to find the C distinction between declaration and definition because I had been using a similar the first object oriented programming language that didn't have the definition the distinction so you have a class and then you have the first member function, the second member function the third member function this was in the days where you have to flip pages and it was very common to find a class where you have to flip 20 pages to figure out which member functions it had and flipping up and down was horrid on a screen it's a little bit faster but it's still horrid the solution for that is either to have the distinction between interface and implementation declaration definition or tools that extract various views of the code in which case you get it anyway so no, I rather want to teach people to use the distinction more consistently and have tools that connect things together in October so what I showed you there I was standard C++ ISO standard C++ else shipped by Microsoft and Canoe and Selang and others very soon it's not just standard it's shipped this is not a science fiction talk and I believe that's true for all the code I showed you I think it's usually a very bad way of teaching it and there's better ways in particular teaching C before C++ is a classical mistake they say C is simpler unless you want to know the details unless you want to use it it's simpler that is, you start out with a richer language I don't have any problems teaching people a vector not even with pushback it's much harder to teach them to use an array because now we have to teach them pointers and what to do when they point out in the white blue yonder early on so I strongly believe that you teach at the highest level of abstraction that makes any sense and if you look at the level I'm using I have a book out called Programming, Practicing principle some practice using C++ and that shows the level I want to be at like I show types bool, char, int, double, string and vector that's what you use in the first few weeks and then you get the the four loops and things like that but bottom up is not all that great I use actually top down to teach a lot of things the way I introduce pointers is to say now how do we implement a vector in the constructor we have to acquire some memory how do we do that have to teach you what a pointer is and what an array is and what the free store is and how do we give it back that's what's in the destructor so I go the other way and I've argued this for quite a few years I've practiced it for quite a few years and I've done it in a large scale for the freshman at Texas A&M University for the last four years using these materials it works at least as well as anything else and I would like to claim better but it's really hard to prove anything in the area of education I think that concurrency and some specialized forms of hardware are best supported through libraries I don't believe there's one kind of concurrency that's best for all applications and everywhere you have to have special purpose libraries special primitive operations special primitive types to do it what C++11 gives you is the standard threads and locked model of concurrency which is the worst model for most applications but it's the only one that's fully general if you want to do special architectures special concurrency models program them within the framework of what's provided by the standard but I do hope to see maybe a dozen specialized concurrency models hopefully being able to interoperate to some extent but I don't think it belongs in the language in itself what do I think of what what do I think about concepts for templates it's a very good idea I've worked on it for a long time concepts as proposed was C++0x and was briefly in C++0x was simply too immature and too complicated to actually work and carry too much overhead at compile time but we got the runtime things down we need more research on it it's being done I would put some decent odds that we would get it in maybe five years I would get very good odds that we have experimental versions and lots of academic papers within the next couple of years by the way, giving good odds I think I've seen the drafts what is your favorite text editor? what's my favorite? it's an old editor which doesn't run on most machines anymore called SAM it has cut paste and snuff and look as the only commands and they sit on the mouse I think I can't stand Emax I can't stand VM I swore off them 25 years ago horrible beasts but basically of the choices I really have and can use, I don't like any of them they're all too complicated