Generic Programming Galore using D
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Alexandrescu, Andrei
Generic programming holds great promise – ultimate reuse, unprecedented flexibility, and never a need to reimplement an algorithm from scratch due to abstraction penalties. Unfortunately, the shiny city on the hill is difficult to reach. C++’s generic power has effectively reached a plateau – anything but the simplest generic constructs quickly turn an exponential complexity/benefit elbow. C++11 fails to be a strong sequel in the generic programming arena, and many other languages don’t seem to “get” genericity properly at all. The D programming language is a definite exception from this trend. D makes short work of the most formidable generic programming tasks achievable with C++, and makes virtually impossible tasks readily doable. It also reduces the relevance of “Modern C++ Design” to that of an introductory brochure (much to the dismay of that book’s author). This talk has a simple structure. It will pose a few generic programming tasks that seem difficult or impossible with current language technology, and then will show solutions in D that solve said problems.
 I think we're ready to roll. Okay. So I landed at Oslo Airport yesterday and I paid half of my credit limit for the taxi after which I got here. I was really thirsty. So I go to the water place and then this lady who's like, you know, what would you like? And I say, I would like some cold sparkling water. She's like, oh, right on. This is awesome. It's like choosing one of those two choices was a genial idea. It was just perfect. A strike of genius there. And she gives me water like I've been like for the last six months in Sahara. So she was incredibly courteous and nice about it. So I can only assume that, you know, Norwegians are all nice people and that that bodes really well for the stock. So hello, Norway. I'm Andre Alexanderesky. I work for Facebook and I'm going to talk about the deep programming language. First of all, I'm going to discuss generic programming. So before that, in fact, let's take a quick show of hands. How many of you actually use a language such as Java, C-sharp, C++ or derivatives? Okay. So it's a kind of quite targeted audience there. This is awesome. For that matter, so how many of you is C-sharp in particular? Because that would be sort of the second. Okay. Great. So that has quite, let's say, okay, mechanisms for generic programming. So let's try to define it. I'm going to go a lot by interacting with you guys. So you feel free to not only interrupt me and ask questions, but actually interrupt me and, you know, make points, help my talk and make it better. So what is generic programming? How do you define it? You know, because C-sharp has generics. Java has generics or at least what they call it. So essentially, what would be generic programming as, you know, as an area of interest? Any ideas? Yes. Yeah. Yeah, it's like, let me think. Yes. Type? Type as parameters. So that would be a sort of a mechanism part of generic programming. Let me attempt to give my own definition because it's many things to many people. So in my opinion, it's an activity. And it goes like this. Well, we want to find the most general representation of a given algorithm. Searching, linear search, binary search, ternary search, there is such a thing. Sorting, grouping. You know, all of the classic SQL, algebra elements, all of that good stuff. These are activities. Like, you know, let me take an algorithm and find its most general representation. So what's the most general representation? That uses a minimum amount of primitives. Like you go in math and say, you know, the angles of a triangle sum to 180 degrees. But that's the consequence of how many axioms. Does anyone know how many axioms? I remember very vaguely there's four and one is like the axiom of parallels which, of course, I've proven in the sixth grade and my teacher was like, oh my God, Andre, what's wrong with you? So you define in terms of as few axioms as possible, as few primitives as possible. Like, you know, what's the minimum amount of humanly possible data structure that can actually sort? Right? So you narrow the requirements down. Let me see if I have a laser here. Apparently I don't. So you make the national requirements. Why does guarantee sort of the best sign of fan in fan out ratio you can ever find? And by the way, big encapsulation should be a crime in 52 states and in Europe as well. European Union, Norway, you know, everywhere. It should be a crime. And here's why. Actually, I was very happy. I was sitting in disclosure talk just earlier today and, you know, the speaker made a point that these are constant time operations or these are log time operations and that's great because a major issue with encapsulation of Big O is that essentially it makes it extremely easy to get to quadratic performance which is, so quadratic on big data is essentially it's, you know, you don't do that, right? If you do need to do quadratic on large data, it's very explicit. So, you know, I'm going to use a quadratic algorithm with the following, you know, with the following improvements and sort of, you know, amendments and, you know, qualifications and whatnot. So it's quadratic but we kind of do it because we have to, like, you know, do like this matrix operation and whatnot. But sort of, you know, getting from linear to quadratic is a very easy step if you claim that you can access the nth element of a list with a primitive, say, oh, yeah, I know how to get to the nth element of the list. I have to just go every step to the way and then people are going to use that as an index, you know, loop and that's going to be a disaster. Do you agree with this? Big O encapsulation should not, people should not do that, right? I'm very happy to see that happen because, like, when lists started, lists said we're going to do everything with lists which is fine because it's going to, lists are going to be able to represent every data structure in the universe and they omitted the comma and what comes after, comes after which is with a blow-up in polynomial blow-up in access complexity, you know, in time to access. So that polynomial blow-up is actually very important. All right. So hope I convinced you that, you know, that's something not to do. And you don't need to regress to handwritten code. This is also very important so you should leave no room below your abstraction and unfortunately my main abstractions kind of do that. They're like, you know what, I'm just going to not, not even claim that I'm about as good as handwritten code. If you really want speed, you got to redo this wonderful algorithm by hand in your own terms as opposed to reusing my abstraction. So these are sort of, this is like, you know, a nice definition of generic program and find the most general presentation of an algorithm and go ahead and implement it. Then you define the appropriate data types that implement those requirements, right? And finally, you're going to leverage the algorithm for ultimate reuse on whatever data structures you're, you're, you're having to have. And ultimately you're going to make a big profit out of it. And well, so that last part depends on your entrepreneurial qualities and whatnot. But this is in my opinion what generic program is all about. And I would add that for me personally, this is, this is one thing I want to do. If computer science is about algorithms, then this is it. This is the beast needs. This is what I want to be. This is what I want to do. This is what, this is kind of something that's important to my life, right? So I want to kind of, oh, okay, so CS is about algorithms and all that good stuff. And generic program is about finding sort of the axiomatic representation of algorithms and structures. And therefore, you know, I want to be there. I want to be part of it, right? So I would argue that this is an important thing. Now you know the classic quote and I kind of, to change a few words in it. I said, you know, premature optimization is the root of all evil. I kind of changed a few words to make it like a weird, premature encapsulation is the root of some derangement. I didn't want to, you know, make it like all evil. I just wanted to be more reasonable about it. Premature encapsulation being exactly this kind of thing. You choose to encapsulate something in a, you know, in a data structure, sort of a generic presentation and you get to, essentially there's friction all the way. So this is sort of a problem. Like, whenever encapsulate there's going to be this inevitable friction and when you compose these mechanisms together, the friction is going to just add and it's going to create problems for the users. Now let's work on a very simple warm-up question and it's going to be very familiar to all of us. It's like, yeah, you know, I want the main function that takes them to numbers or more and it's very surprising that in this day and age, I mean, we've been doing like computing for what? Like, I don't know, 75 years now and it's kind of weird that people still need to discuss a passive one and this should be a solved problem. The simplest possible algorithms one can invent and it's kind of amazing that they still debate like, you know, how do you do a minimum? Oh, here's what you do and you know, don't care about that but, you know, that's going to be inefficient and that's going to be like impractical or that's going to be, you know, not difficult to use. So you know, the dream mini function would be, well, let me take the, you know, minimum of many arguments as many as I want, I want to take minimum of AB whatever. I don't want to, you know, have a nonsensical code of minimum of one element or zero elements, right? I want to work for all ordered types and conversions. So I want to take the minimum of an integer and a floating point number and what should that give me? The minimum of an integer and floating point number, what type should that give me back? This is a test you're listening. Yeah, okay. The gentleman says floating point number. Yeah, so you've got to kind of, you know, fall back to the most general of the two. You can't think of a sort of inclusion polymorphism there. How about the minimum between an assigned type and an unsigned type? So this is going to be more interesting. Yeah, so, you know, it kind of gets into the, into discussion already. It sounds like we're debating here, right? What the hell is going on here, right? So how about the, you know, a simpler one. The maximum between a signed type and an unsigned type. How about that? That's easy because the maximum is always going to be unsigned since one of the, one of the branches is unsigned, one of the elements is unsigned. So definitely it's going to be greater than or equal to zero and therefore I'm there, right? And then it comes to, you know, the whole discussion about size and all that stuff. Like, can I represent everything representable? So we get into this interesting notion which is, you know, which, you know, somebody who's into dynamic typing, you know, they kind of, I lost them at the title of the slide. It's like, yeah, I know how to define me. It takes me one line and I don't care about types. Like zero, I have zero concern, can take the minimum between a string and an apple and a banana and an orange if I so want. And it's going to give me something that I don't care much about the type. But here we're firmly anchored in a realm where we do want to be able to do such judgments, right? Prior to runtime, we do want to issue such judgments. And interestingly enough, it turns out that minimum maximum, two functions of which type depends on the types of the input in interesting ways. Because again, the maximum between an assign and assign is unsigned and that doesn't apply to min. So they're not equivalent in a sense, right? So all of a sudden we get into a universe where weird things are happening and these very simple primitive functions are worth talking about, right? I can only hope by the time we all are very old and crutchety and, you know, we don't care about like, yeah, I used to be a programmer, I don't care about it anymore. You know, I have a pension, whatever. So at that time, I hope there's no good, there's nobody's going to talk about this. Because yeah, I know, you know, min, it's like there, everybody has it, everybody uses it. There's no more controversy surrounding it, right? Okay. So not to work for everybody and we want to decline incompatible types without prejudice, right? Let's see how we can do that. So indeed, we have very nice and essentially like we wanted to take generic programming C++ C sharp style and make it like absolutely trivial to use. They should, essentially it's an embarrassment to not use it because it's so simple and it brings you so much more generality. It takes just a couple of characters more than writing min for ints or for floats or for doubles. I say well, min of left type and right type LR, they could be different as I just said. So I'm going to take left hand side, right hand side and I'm going to do the classic switcheroo. But here's a question for you guys. Why did I put RHS less than LHS and you know, usually you would put like LHS, left hand side, less than right hand side. Why did I swap the two arguments? All right, who can tell me this is going to get the following. I have here some delicious handwritten cards, invitations for one person to the Facebook party. It's going to be an open, you know, happy hour event. Six to eight tonight. Free food, free drinks, free chat. There's no pressure like, you know, you got to apply to Facebook or whatever. So you get at a very hip location in Oslo, which is within walking distance. So here they told me not to tell you because then everybody's going to, you know, kind of lynch me and destroy me and get these cards, okay? So who answers this question is going to get one of these cards and I have a few more. So let's see, why did I swap the order of RHS and LHS? Because the intuition is like, minimum of A and B is, oh, is A less than B than A, otherwise B. Okay. Oh, come on, I'm going to go along to the party. All right, so here's the answer. The answer is stability because you could have types that are partially ordered. And what I'm saying here is, well, in the case, so I'm going to swap the order of LHS and RHS, only if RHS is positively less than LHS. And in all other cases, including the case in which they are not ordered, I'm going to preserve the order of returning LHS, the left-hand side. So this is sort of a solid reason because, for example, if less than is like some string insensitive comparison, you want to kind of, you know, keep the left guy by default and return the right guy only if they're really ordered. So this is sort of an interesting little detail and it's amazing, again, that we need to still talk about this. This invite remains open. So I'm going to give one for each good question I get and, okay, all questions are good. All right. And by the way, so the other speakers told me, like, Andre, you know, Norwegian people are really socially shy. They don't ask questions and stuff. So in America, I would have gotten like a million questions already. And he's like, I'm getting some chakras, which is good. It's a good sign. But let's ram this up. And by the way, to ram this up even further, I have this wonderful Facebook t-shirts, which I'm going to get for really good answers, really good questions or really good answers for that matter. So let's ramp it up. So far so good. So we have the first min, which is like a two-liner as expected. I mean, I wouldn't expect it to be any longer. But the nice thing is that we have two genericity here. The code expands to different functions depending on the input types, which means it's just as good as you typed it by hand, right? The counterargument there would be, well, yeah, I have too many functions now. So it's big code. There's a lot of bloat there. And there are like compiler techniques to avoid that and to kind of merge a lot of instantiations into one and stuff like that. But for a function this short is going to be in line. So actually typing min of A and B is going to be just as good as actually typing A less than B, blah, blah, blah, blah, with one evaluation for A, one evaluation for B, which is perfect. All right. Well, let's make it, let's kind of ramp it up, take it once the further. Let's make it work for more than two arguments, any number of arguments. Because I can take the min of four numbers and that's entirely reasonable. So we have this very nice variadic feature there. Oh, look at that. So I have this very nice variadic feature. I say, oh, you know, min of t's dot, dot, dot, and I'm going to take a list of t's x and that's a sort of a compiling construct. And I'm going to do something very interesting here. Let's say, well, during compilation static if, so during compilation if I happen to pass more than two argument, I'm going to recurse. Right? So I just, you know, just classic recursion, right? Min of the, the min of the first two and then the rest. This dollar is like, you know, go all the way through the last element in the, this slice, right? So take the min of the first two and then, you know, the rest of them. Now notice that this works only, this, this applies only if the length is strictly greater than two, which means that x of zero is well defined, x of one is well defined, and these guys are well defined. Very nice. Well, otherwise I know what to do. I already had it on the previous slide, right? Just take the, the min of two elements. So well, now I can write a min of a plus b, 100, and c, or whatever I want. And there are two interesting things, things here to note. Number one, we're not dealing with arrays here. And that's important because arrays already kind of bind into a specific representation, into specific operations, into specific, specific way of doing things. This is, these are not arrays. These are compile time arrays, if you wish, which do not have a kind of, you know, representation as arrays during runtime necessarily. So these are just sort of lists of types and lists of values, which is really nice. And I get to do operations during compilation, I get to do operations during runtime. Some more, and this is probably even more interesting, this is not classic recursion. So even if it says, okay, let's look at the word min, how many times we have it? One, two, three, three times in the definition only. But each of these three names is a different thing, which is nice because I use the same, I use the name for the concept, not for the, you know, for the incarnation of the concept. I will go crazy if I had to define like min one, min two or whatever, right? So this is not recursion because each of these sort of sub, you know, sub invocations of min is on a shorter list of arguments, right? So I call it for, you know, the min, the big min is like, you know, I kill it for 50 arguments if you so wish, let's say five arguments more reasonable. But inside is going to recurse, pseudo-recurs back to minimums of smaller sizes. And those minions are going to be different instantiation of the same thing. And each is going to have its own address if you wish, it's going to be its own function, right? So all of a sudden I have this notion that I recurse during compilation, but it's not a runtime recursion. And that's good because it's efficient, right? It's as if I, again, as if I kind of sit down and write the comparisons myself by hand, right? And I have the stack, if min were like all of them in space, that would be terrible, right? It would be like kind of a shameful thing to have, right? So very nice. All of a sudden I got min for many arguments. Questions so far? Yes. Yes. I'm sure for God's sake, what's your consideration of stability? Haven't you forgotten to consider stability? Okay, let's see. What's your name? Michael? Michael. Michael, let's see. X0 greater than, no, because this is min and this is greater. So I kind of, you know, okay, let's notice this. So I hear you use RHS less than LHS, and here I use X of 0 greater than X of 1. So it's the same thing just I wrote it the other way, just to confuse people like you. All right. You see what I'm saying? Yeah, so essentially what I'm doing here is like, if X of 1 is definitely not a problem, definitely less than X of 0, then I'm going to return X of 1, which is kind of the weird thing, and in all other cases I'm going to return X of 0. So well, I think the discussion on stability would be more interesting with a better operator because min is kind of, you know, what you see, what you get. Nevertheless, Michael, congratulations. Thank you. I'll see you tonight. You got a date. All right. If you use functionality before you have two slides, I can tell you a little bit. Uh-huh. Ah, the news function, you deserve a card or a t-shirt. What do you want? It's such a good question that you deserve either what do you prefer? You want a t-shirt? Yeah, I'm checking a flight. Oh, okay. Never mind. Okay. So the question was, well, you have one t here, which means you kind of lose the nice, remember like LR, like, you know, inflow or, you know, unsigned in whatever, right? So it could be like nice things here, but here kind of losing that. Well we're not, because t dot dot dot means a list of any types. There's one name for it, but it's a list of any, you know, you can have inflow, double, unsigned, char, whatever, right? So that's nice. So this t here stands for as many types as you want. And whenever you refer to x of zero, t of zero, whatever, it's going to kind of instantiate the thing with the appropriate type. So it all holds water. Yes? Could you mix variables and list of variables here? Come again? Could you mix? Could you mix? You're calling, you're putting variables, right? Because it's going to be five, a hundred, one kind of. Right. Could you put in a list there as well? A list of variables? A list of variables. So, okay, so here in this case, t stands for a list of types. So I can say t at zero, t at one, t at whatever. And x stands indeed for a list of variables. And indeed, x of zero is like one variable. And what was the sort of the, where we're driving at? What was the sort of ultimate? You can recall, you can recall a function, which is all m, which was named, you know, 300 and c, right? Yes. What if you put a list in the function call? What if you put a list in the function call? In that case, if you just, if I just put like, you know, let's say min and I, min, IMP or whatever, and just pass x into it, then it's going to be automatically expanded. So it's going to, there are other means to encapsulate things like that and kind of keep them together and expand them explicitly. And actually that's kind of a cool thing to, to deal with for which reason you deserve a card. I actually have a hard question. Yes. Oh my God. You want two cards? You have a girlfriend? Thank you. You could have a list of lists, right? Why wouldn't you just write a for loop? If you have lists, yeah. We could write a for loop. This is just the same because you have a static for each. So you have a static for loop that you can use. I wrote this because, you know, a function from is cool and everybody's into that. So if they say like, oh, for each one, you know, back in the 70s here. So you know, this is, oh my God, this is awesome, you know. So yeah, you could use a loop as well and it would be, there's a way to write a static loop and it's going to validate, expand in compilation. Great. Yes. What happens if you call min with just one argument? What happens if you call min with just one argument? Are you in town tonight? You got a date. Feel free to pick it up later, okay? So just a second because I didn't answer that. I gave him a card that doesn't, you know, preclude an answer. So right now we're not good there because you can call min with like zero arguments or one argument that's going to kind of explode. It's not going to do well because, for example, like for, if you go with an argument, this guy is undefined. What the hell, right? Yeah, you're going to get the compile time error, but it's not going to do well because you're going to get the compile time error, but it's not going to be like, essentially I consider it failure of defining min properly. So you're ahead one slide or couple of slides. Yes, question in the back. If you're dealing with a clause language and you would probably go in a library. Yes. That is correct. So the question was, the question was, well, number one, D is a compile language and presumably going to put min in a library, which is, so you can just Google for D program language like D lang min, you're going to find it. And if two applications are using min, or if one application happens to use like a million min or whatever with each with different number of arguments, which is kind of weird, it's not going to happen, but, you know, see what I'm saying. So there's going to be some binary code duplication there, right? So yes, you can't put min in a dynamic library. This min, you cannot put it in a dynamic library. This is a sort of an interesting trade-off. It's the other side of the trade-off, which is, well, if you want generic and if you want kind of expansion in compilation, all that good stuff, you can kind of encapsulate that in a DLL, if you wish, and kind of make it the same code, the same binary code available to everybody. So there's sort of, there's two extremes in this spectrum, and this is at the end of the spectrum is like pretty much everything is done in compilation, and it's as if you write the code by hand. And there's, of course, techniques that take you to all the way to the other end, which is, well, I want to actually write the function and lose some of the benefits, but at the same time gain some better binary reuse. So these things are fundamental intention. Are you in time tonight? Okay. T-shirt? Okay. All right. So, so far so good. There's one more question down here. Okay. Up there? Okay. Let me know. Yes? Is there any way to enforce such a sense in the veritable argument? Is there a way to enforce that T is actually all T's, you know? Yeah. Actually, there's a predicate called all satisfy, which is implemented in the library, and it's, you know, all satisfied T's and or whatever. Okay. Awesome. All right. So we're at, you know, you were on slide ahead because we want to reject nonsensical calls. We want to say, well, I'm going to accept min of T's, only if the length of x is greater than 1. And here we stumble upon a very interesting feature of D, which is I can restrict statically any function I want in any way I want with anybody predicate. Right? So all of a sudden I can say, well, you know, I want to take min only if the length of these guys is 1, and if not, min just disappears. There's no min for one argument or zero arguments. It doesn't exist, right? Because it kind of, you know, takes it away from the food chain, which is nice because if I, at some point I want to define for whatever reasons my own function min that takes one argument, I could do so because this min is not going to compete with that guy. Right? So this is sort of good encapsulation of modules. So I just said that. And you know, of course, we need to do more work, which would be sort of some sort of interesting thing to talk about. Like, well, I want to kind of say if x length is greater than 1 and if, so, all satisfied T's a numeric type or it supports comparison and all that stuff, so you have to only accept types with a valid intersection, and we only want to accept types comparable with less than. Right? So you know what? Let's actually dive into this a bit because I think it's interesting to know about. Right? So I'm going to throw a wall of code at you here, which is not that difficult, so bear with me. So the task is given a list of types, the T dot dot dot. Let's find the common type of them all. So let's find the sort of the least common denominator type of a list of types. It's kind of interesting. Like, you know, if you think of it like I'm giving a bunch of types and it's like, find me the type that everybody converts to. Right? Huh. So, well, if I have one type, then my job is very simple. I'm just going to return the first type, the first and only type. Otherwise, if I have more than one type, well, let me kind of do this very funny construct here, which is type of an expression. And the type of an expression is going to take the expression, not evaluate it because it's all, this all happens smoke and mirrors during compilation. This is not going to, oh, I'm running this and I'm going to evaluate that and it's going to try that and it's not going to work. It's going to throw or whatever and then I'm going to fail. Now, this is all during compilations. The compiler is like, oh, let me test the type of the conditional expression like true one. And if it's true, then I'm going to return the first type in it. Otherwise, I'm going to return the second type in it. And this anything is giving the initial value of that particular type. So this is actually a value of type T zero and this is a value of type one. When you do the question mark operator against two different types, what you're going to get as the type of the whole expression, they're common type. Because like in C sharp, if you take the, you know, condition, floating point number and integer, you're going to get the floating point number and so on, you know, objects, it works like, you know, actually they find C sharp finds the common ancestor, the close, the, you know, the best common ancestor of two types, which is kind of very nice, amazing, right? And this is very nice. So essentially with this operator being designed so well, right, you get to actually use it during compilation to figure out the type, the common type of two guys. So wow. So at this point, I'm, well, I'm greater than one. And I'm going to say, well, if this is actually a type that works, and I'm going to call it you, then oh, okay, awesome, I'm going to make progress here because I'm going to recurse to common type with you and the other types in the list. And I'm going to alias that to common type. And if nothing works, I'm going to say, you know what, I'm going to give up. And the common type of these types is void, which means there's no real type that's going to work there. Right? Okay. So let's recap. If I have one type, it's obvious. If I have more than one type, I take the common type of two types by the magic of this type of expression. I give it the name you. And if that works, I'm going to say, well, then common type is the common type of these two types and then the trailing other types. So recurse, right, in a way. And yeah. What does the? What does the? The bang. The bang. Oh, the bang is template instantiation. So C sharp chose the, you know, angle brackets. C plus chose the angle brackets. There's any amount of pain that has been caused to parcel rightness and developers because of the angle brackets. And D went like, you know what, I'm going to instantiate with bank brands. So that's how we roll. Okay. So let me note something. Let me, this is sort of a unit test. Well, Steadica said that the common type of in short and long is long. So let me make, take a break here and make sort of a side point. This is the kind of stuff that developers like, you know, as I'm, I want to get work done in this language, right? This is the kind of work that developers don't care about that much. It's not typical. Like, oh yeah, at my day job, I figure out the common type of three types. You don't do that, right? This is the kind of stuff that who's worried about, like who's doing this stuff? What kind of people? Like, who, who, who, right, what? Compilers. This is the kind of stuff that the compiler writer is going to be busy about. Yeah. During my compiler work, I need to figure out, I'm given, I mess with types all the time. So I need to take, yeah, the common type of these two types, I know, I don't know what it is, right? So this is the job of a compiler writer. And the fact that, and it's actually in the compiler, it's not in user code, so it's, it can't be part of the target language that you're using. So we're getting to this really weird thing. And it's good weird, I would argue. We're getting to this weird thing where you do type manipulation, kind of compiler grade, if you wish, right? Kind of, you know, compiler, I'm a compiler pro and, you know, I'm kind of doing compiler things. But, you know, it's not really compiler stuff because you're doing it in the target language, in D. You're not doing it in the decompiler, which may be written in other language. You're doing it in the library, in there, in the target language. And you're manipulating types and kind of figuring out things about types and interest in this introspection kind of thing. And it's all static and it's all great. So this opens up a lot of nice possibilities. Like, you know, the D standard library has a bunch of, you know, traits like that. It gives you the common type of types. It can, here's a nice one. For mocking. You know what the white hole is? White hole. White hole is like you have an interface. It has an influence, like it defines, like, you know, seven methods or whatnot. And you find a white hole, which is the opposite of a black hole because it rejects everything. So you find a class, which is an implementation of the interface and whatever you call, it's going to throw an exception. That's a white hole, right? And it's used in testing and in, you know, people use it for mocking and for things like, you know, I want to implement just one function of this interface. I don't care if the other should throw because I don't implement them, right? So I see not. So I see people kind of having seen that. And actually in Java, it's an idiom. Like people say, oh, yeah, I went into a white hole here and people are in prayer, like, they're like, yeah, I have a white hole here. And in other languages and so on. But it's all done by hand. So it didn't even occur to people that, oh, actually that's an automatic thing to do. Right? And why didn't it occur? Because it's the job of a compiler writer usually to do that kind of stuff. Yeah, let me kind of add a feature to the language that implements this white hole thing. Right? However, in D, there's a white hole thing that's, that uses completely like standard features of D that are available to all programmers. And it's kind of very interesting that you get to implement such things, like for each member of the class, generate a function that's going to throw an exception. This is pretty cool, right? So okay, parenthesis closed. Yes? If the contract of the interface should not throw, then you have no business throwing. That would be a programmer error, right? Because it shouldn't instantiate the white hole with that interface. But it's a good point. And in Java, it would be better off because you have the checked exceptions and all that. So anywho, that's a good point. Well let's use this common type guy. So we're back to many of these whatever in the length of the list has to be greater than one. And then we say, well, type of the common type of T dot in it less than common type of T dot in it is bull. So what I do here is I take the common type of all these and I create the value from it by means of dot in it. So dot in it means, you know, give me the default value of that type. Like for instance, like dot in is like zero, right? And for characters, like, you know, all ones because that's an invalid character and that kind of stuff. And for floats is nan and that kind of stuff. So but I don't care about the value here because it's all compile time stuff. So I say, well, let me take the type of common type of all these dot in it is less than common type of all these dot in it. And that type is got to be bull because that's what mean asks for. And in these two lines, I got to say the types have a common type actually in fact, it's not void. And the types are comparable. And you know, there's more than two, more than one, right? So we have this nice Boolean condition and then with the body is the same. But this point, we got actually we got like full bore because it's the mean that, you know, this is what I wanted in the first place, right? So I kind of have satisfied all of my requirements. So again, it's amazing that we need to talk about this. The fact that different languages take so wildly different stances on this, especially with regard to efficiency is a sort of, you know, it's a slap on the face of, you know, our community as software developers in general because a very simple thing to do. So I'm going to go back to this. You're losing the? Yeah. Okay. So I'm using a good point. So the point was you're here using the less than operator and here's in the greater than operator, right? Oh, not here. Sorry. Yeah. Wrong, wrong laser here, right? In D, they're equivalent. In D, using this is the same as because they're all boiled down to the same comparison. It's a good point for which reason are in town tonight. All right. Congratulations. Nice shoes. Yes. This is awesome. Okay. All right. So, yep. Okay. So this is a very good question. I'm going to repeat it in a second. I mean, time tonight. Okay. So the question was, well, if I have an unsigned internet named, it's weird. Let's say they have the same size for starters, right? They have the same size, 32-bit or whatever, right? 32-bit, one unsigned, one unsigned. Am I going where you want it to be? Okay. And then I want to take the min of the two and, you know, what's going to happen then, right? Well, I guess it's okay because Indy's going to be able to represent everything. The max, okay. So let's switch to max and now I have an unsigned and I have a signed and I take the maximum. What's going to happen next? Who can represent everything? The unsigned guy is going to be able to represent everything. So if you return the unsigned, you're in good shape already. I think the problem comes when you try to compare an unsigned 32 to a signed 64 and then you get into problems. You have a common type between the unsigned and the unsigned. Well, Indy has the following principle. So you know, the question was like, what's the common type of signed and signed and stuff like that. So D follows the following principle. It's quite similar to C, like there's like a large part of D that's similar to C and kind of inherits in many ways. And therefore, people, people, it's a practical thing. People take a bunch of C code and they put it, they throw it in a D file and they hit compile. And then we have two traces. We succeed to compile, oh, okay, the simpler one. We fail to compile and that's fair because there's stuff that, you know, this is too unsafe for us, you know, it's not our taste, not our cup of tea, too unsafe code, whatever. That's fine. But let's say we succeed to compile that program. And if we succeed and if we have different behavior, that would be a disaster because people would come like, you know, well, I took this encryption, you know, RSA algorithm, encryption that's like, you know, 7,000 lines of C, like paste it into a D program. It compiled what it doesn't decrypt. It compresses, actually. You know, something, I don't know. That's something else. You know, it's, whoa, that would be weird. It's, yeah, we don't want that to happen. However, whenever D compiles just C code, it's going to do what C does. So it kind of has this nice preservation of semantics. And C has a rule. It has many, you know, several rules, but it has one simple rule which is, you know, expression involving sign and unsigned types, unsigned kind of wins most of the time. So actually the way I like to say the rule, you kind of ingest, is like if an unsigned is within one mile radius of an expression, the expression is going to be unsigned. That was a joke. Thank you. Awesome. Okay. So because of that, we have this unsigned in 32, signed in 32, unsigned is going to win. And that can cause some problems which we eliminate through other means. But anyhow, I think the main point here regarding this whole unsigned comparison mess is that if you get to manipulate the types any way you want and actually mean in the D standard library, does do that kind of, you know, semantics sensitive typing which is very interesting. Yes? When you have reference types, this would be called reference, just know. When you have reference, yeah, this would be null. Okay. Yeah. But that's fine because we don't evaluate this. We just, yeah, we just look at the type. All right. And you know, there's all this discussion like, you know, people say it's good to have like non-null types, right? Types that can never be null. And this has been a sort of a sort of thumb for D because D has null and we kind of decided to make a library solution for it and so there's a non-null type right now which is being discussed which is kind of interesting. All right. Am I supposed to be about done? No. Someone finished early. That's nice. Okay, though. So far so good? All right. Well, where was I? Okay. So this kind of, what happened here? Okay. So far so good. Okay. Well, so it's one thing to say, well, I want to take the minimum element of like three guys. That's fine. But what if I take the minimum element of an array or a stream or file or, you know, kind of a database or whatnot. So at this point we get, okay, so it's sort of more of the same. I'm going to take min from a range which is some sort of collection of elements that can be iterated through. And this whole range thing has sort of exploded in popularity with D because it's a central concept to D which means, you know, C++ is iterators, LISP has lists, S lists and whatnot and D, 4D ranges are sort of the thing. So we say, well, if I have an input range which has the first element can be compared with less than, then I'm going to do a for each loop. I'm going to say, yeah, for each element, just, you know, do this and do that and do that, the other. And that's a nice implementation of min. And before anyone mentions it, I should tell you that, you know, you actually don't want to write this because it's a reduced function in the standard library that's just reduced with min, this range, and it's going to just work, right? So this is kind of showing you from sort of almost first principles kind of thing, like, you know, bona fide, you know, good developer code, I'm going to write a for loop and I'm going to do that and stuff like that. You don't want to recurse because then you have, like, you know, you've got to be careful about making it tail recursive and all good stuff. So this is a good example for the sake of a presentation. Now, I say, one nice thing is, like, you know, I don't need to specify the type, it's going to kind of take care of itself. I say auto, type deduction for the win, right? And what else is interesting here, I'm taking the first element, I pop the first element, I guess this is pretty much right itself, right? For each knows how to pop elements from a range. So I guess, you know, if you squint a bit, because for example, I didn't define this guy is an input range, which means he has a front, has an empty, has a pop front, that kind of stuff. But if you squint a bit, I'm sure you kind of get the gist of it. Great. And it's nice because it works over anything that can be iterated and this is, there's no amount of overemphasizing I can do here because this sort of generality is typical to for generic programming, which is say, yeah, I can take the, like, in Java it's very typical, like, yeah, I know how to take the middle of an array, but that helps in nothing in terms of taking the middle of a singly linked list. And that in turn doesn't help me much for defining the middle of a doubly linked list and so on. So, you know, this kind of generality is not actually very well represented in some languages. Here essentially this is sort of the very essence of the min algorithm, you know, the loop over anything because anything that has these primitives can be, you know, it can min over those, right? So this is sort of the essence of I want to take the minimum of many elements of arbitrary number of elements. By the way, let me ask you this. Do you know edit distance? Right, okay. Levenstein, edit, like, you know, I have two strings. How many of these does it take to transform one to the other? And what kind of data structures does it work on? Like what is the minimum data structure? You know, edit this, like, look at these guys, the dynamic programming, interviewers love it, you know. Erase, strings, yeah, so it's typically for strings, but more generally like a race, right? Yes? Lists. All right, so actually it's kind of very interesting that edit distance works on lists, but actually I saw an implementation in Haskell that the author kind of didn't figure that out and said, oh, I'm going to use a race here. So actually edit distance work on lists. This is the minimum you need. You know, you don't need really a race. So a race would be sort of a total order because they have to be contiguous on that stuff, and you don't need random access. You don't need random access for edit distance. And this is the kind of job you would do as a guy who does that, who does generic programming. You would think about these things, like, you know, what is the minimum data structure that edit distance works on? And this is the minimum thing that min works on because here's an interesting thing. For min, do you need to ever look back in the range? Do you need to kind of remember, oh, the fifth element I saw, oh, fifth element, nice. The fifth element I saw was that, you know, this is important to me. Is it? No, because you kind of just walk the bridge and the bridge can kind of just sink behind you, right? You don't need what's behind. So you're going to look at the current element that you don't care after you're done, you're done. And that's an input range. It's a stream. It's something that is evanescent. It doesn't have a presence in memory. So you can take the meaning of a very large file and it's going to work. And that's, you know, SQL actually is big on that kind of distinction. So this is very nice because input ranges represent exactly that notion. It's an input range. It doesn't have to be in memory. It could, as the example shows, it could be an array. I don't care because an array is better than an input range. It has more stuff to it, so much the better. For min, I don't care about the good stuff that array has except for the fact that I can actually look at one element at a time. Awesome. Well, argmin is a very, very popular, all right. Nothing happened. The situation is under control. All right. I walk too much. The camera folks are going to kill me. Okay. So argmin is sort of a popular notion for machine learning people. Like, you know, I want to take the minimum argument, you know, the minimum index of the index of the minimum element, the smallest element. So that's not much more difficult. I just have to kind of do a bit more work by kind of cashing the stuff and kind of saving the candidate. And you know, so my result is going to be the first element. I'm going to cache the function and all that stuff. What I want to emphasize here is this. Argmin alias fun. So alias fun is a higher order function, right? So argmin is a higher order function because I want to say what is the minimum, you know, argument in this range for which fun gives you the minimum, right? So I want to say argmin of square root or whatever. I want to, that's easy. Argmin of tangent or argmin of whatever, right? And at this point, I have a higher order function argmin that takes an alias and a range and is going to use the alias to invoke the function. And the nice thing about pass by alias is that it's extremely efficient. So one known issue with many functional languages of today is that as you stack these nice subtractions, map, reduce, and you know, higher order functions and stuff, they all have one in direction each. So by the time you have a stack of like seven, there's going to be like, you know, seven, literally like seven in directions to get to where you want to be, right? Pass by alias, short circles that by saying, you know, I'm going to instantiate for this particular function, I'm going to make a separate instance for this other function. So this is pass by alias. And again, the usual discussion of, you know, co-generated size versus dynamic library size and, you know, that binary code reuse that you asked, you know, these kind of caveats still apply, of course. So argmin, right, takes a function. Let me see if I have an example for argmin. Oh, thank God. Okay, great. So I have, well, I have a number of strings or whatever. And I want to say, well, which string has the smallest length, which which string is the shortest in this input? So I have the string and I apply this lambda, which maps anything to its length. And that gives me sort of the, what's the name, a one. It's going to be, give me one in the end. So with this, I kind of talked about things like, well, let's talk about, like, you know, what do we take to write a good, a nice min function, which is completely reasonable? And we figured out, you know, there's a lot of wanting solutions. But then we discussed, if you do the appropriate type manipulation, it's good. And the question is, you know, how can we put the means in the language to do such kind of time, type manipulation? And I talked about things like static if, which is great. I talk about, like, pseudo recursion, which is great. I talked about pass by alias, which is great. Okay? So this point here is very important. Because I have, you know, there's a lot of talk about, like, you know, I don't care about static languages. I'm going to do dynamic languages and such. And at least for my kind of workload at Facebook, you know, I think, I think this is going to be more general because big data and, you know, that kind of stuff is going to be more of it, not less of it in the future because the amount of data you play with and the amount of interesting things you want to do with it is just going to grow. And computers are not going to get any faster. So the question is, you want to distribute the thing. And at the same time, you know, your speed of processing is going to be proportional to the number of machines you use, but also proportional, like, in a very direct way, like, there's a multiplication there with the speed of each component. And we get to this point where we're asking ourselves, like, you know, I can distribute this thing very nice, but then it depends on the speed of each component. And if I can't make it fast enough, it's going to hurt me. And actually, even if I distributed it, there's a guy who says, I'm doubling the number of machines. Well, you're going to double the amount of power needed by those machines. And this is the major limitation here. I'm really digressing here, am I not? Okay, but I think this is nice. This is interesting to talk about, right? So the power needed is humongous at Facebook scale. I can't give you specific numbers, but I can say that every 1%, every 1% saved in efficiency of the site. And think of it that way. One person, like, many people say everything below 10% is negligible, right? So I'm talking about 1%, and I mean, people, like, work on a fraction of a cent, 1%. So 1% saving of speed, like, increasing speed of the site is a very significant amount of money in power costs of data centers alone. And that's the case for Facebook. It's a case for Google. It's a case for Amazon, Yahoo, and many others. And there's an increasing number of these companies that are going to have to use power as they're defining means of calculating costs. So that, for that reason, you can't afford often to say, you know what, I don't care about this, but it can, yeah, seven directions, I'm cool with that. You can't afford to be cool about that, quite literally, because it's going to be hot, right? So the machines are going to get really hot, right? All right. If you're more interested in that kind of topic, you should come see my second talk today, which is going to be at 3 o'clock in room 2, which is going to be about a very nice jit architecture that we've done at Facebook. I'm very honored to be part of that team now. And to see how, you know, exactly what it takes and how we did it to accelerate Facebook for 1 billion users. The process is closed. So now, let me kind of change gears a bit. Because, you know, many people say, generate programming, generative programming. And many people say, you know, there's this whole genetic programming, right? Which is unrelated. It's like machine learning, right? Genetic, we don't do that. We don't talk about that here, right? But there's generic and there's generative. Can you define generative for me? Generative, generative. Well, it's, I mean, if I didn't know anything about it, I would say, you mean, say, generate stuff, right? And actually, the reality is very close because it's programs that generate programs. It's code that generates code. Which is, oh, interesting. Let's see. Well, there's a connection here because generic programming very often requires specialization of algorithm which we want to generate automatically. And very often the specification is present in a DSL, domain specific language. Tell me a DSL that you use every day, day to day. Talk to me. SQL. SQL, awesome. This side, didn't talk much. Come on. I swear it, you use every day. Rejects. Not everybody should use it. I'm not saying what it should be using. You know, rejects is everybody's using it even though they shouldn't or whatever. So rejects, a lot of us use it, right? Make files. I mean, come on. It's a DSL. It's like, you know, and whatever, you know, whatever you use. What do you use? What's the latest and greatest? And? Is this what? SCANs? Who's using SCANs? All right. Who's using the Microsoft built-in whatever, right? Okay. So that's sort of, even if that guy is sort of a DSL, although you manipulate it graphically, all right? So very often you have this DSL notion. I got make files. I have rejects. I have print tests, format specifications, you know, string templates, all that stuff. All of that is DSL kind of stuff, right? That's very interesting. So what do we do about implementing these DSLs? Well, one simple solution is like, well, we're going to kind of make the language, the host language look like the DSL and we overload the operator, some of that good stuff. And I don't think that's a great thing, but, you know, whatever works. And I gave some examples already. Some more interesting example are EBNF grammar, right? And to define a language compiler. Portable expression grammar, this is all EBNF on steroids. SQL was mentioned. And, you know, to try to force every of these, each and every of these DSLs into the same host language would be a bit forced. So indeed, we have a different approach which is very interesting. We kind of stumbled upon it. So we're going to use it with native grammar. We're going to process the grammar in compilation and we're going to generate the code accordingly. It's not a macro system. It's sheer code generation from strings. And let me start with a little insight. So this is an absolute classic, right? I don't need to talk about, like, how do you implement factorial in a language that has loops? Yes, this is how you do it. Okay, so this is interesting, but here's the thing. Well, I have a factor of 10 and I get an auto. I kind of, this is like a U long. F1 is factor of 10. And I say static, F2 is factor of 10. When I do that, the compiler is going to evaluate the factor during compilation. Okay, this is how I'm going to, all of a sudden people walk up from, you know, what, what? Okay, so this is what happens. You have one body, but you can actually compile it and evaluate it like classic, like any imperative language would do, but you can also, with the same core syntax, you get to evaluate during compilation as long as you evaluate within a static context. Huh, what the hell can we do with that? Well, let me tell you about the second component of this ploy here. There's a mix-in keyword that says, you know, give me a string and I'll make it into code. So give me a string and I'll compile it, right? It's like eval, but it's just compile time only. So I can actually call a function and the function is going to be evaluated in compilation. It's going to give me a string and I'm going to transform that string into code, which is, oh, what's going on here? So, okay, so we have two things now. Compile time evaluation, we have mix-in. And at this point, I got to imagine we had a big, like, oh, my God, because you get to generate strings with compile time evaluation and you get to mix into new code. And that's how Whitehall is implemented, by the way. Right? So you get to actually do real work during compilation and mean it, like, you know, real, like, actual work. You can create objects, you know, do stuff, right? And then you get to generate strings during compilation and those strings, you get to actually say compile the stuff, right? All right. So this is kind of a big insight. And here's how D does bit fields. D does have a bit field facility like C because we thought it's like, you know, too low level to dirty our hands with it. But it accepts a very simple mix-in function that takes type, takes name, and takes width. And you give it more of these guys and it's going to take care of generating all the code that takes care of the bit fields, you know, all the masking and all that, you know, rotation and all that stuff. And all of it is library code, it's not in the compiler. But this is just the start. I mean, you know, it can get really, really interesting. I mean, consider this. There's a work by Philip Seagal, which is, you know, he defined a grammar parser and the code generator and you can, you have a simple expression and value to here. Expression is like factor and, you know, more factors and then I have an ad expression, which is plus, minus, plus, minus, factor and whatnot. So you have this grammar syntax in a string. That string is passed into the function called grammar, which is defined by this guy. And the result is a string of code, which you're going to ultimately mix in into your decode and congratulations, you got yourself a parser. This reminds you of like Lex Yak and Antler and derivatives, right? But it's all indeed, doesn't need any extra kind of program, right? And it sort of holds water in a, oh, I'm kind of almost over the time here. Sorry for not mentioning that to me. All right. So, very easy to kind of play with this. But you know, my point here is that it kind of holds water because, you know, there's, the D grammar itself can be expressed in 1000 lines and it generates actually 3000 code, 3000 lines of actual parser code that you actually, you put the grammar in D and it kind of parses it with D and you generate D, which you compile and you compile is D. Oh my God. Okay. I'm not even sure I said that correctly. All right. So you can think of it as a highly integrated Lex and Yak. And last point I would like to make before I go, you know, and Jeremy and whatnot is an actual practical result. So there's a regex which is kind of the classic thing. You can take a string, standard input or whatever and you make it into a regex and that's fine. This is sort of the classic thing. Static is CT regex and it takes the string during compilation and it does its own specialized automaton generator in there. Now question, which is faster? The same string. It's the same regex. Which is faster? What do you think? So the first is I kind of bonafide classic regex that people do today. And the second is takes a string, looks at it and generates a specialized automaton just for that particular regex. Yeah. The second is going to generate its own state machine. The first is going to generate a generic state machine which is going to work for all regex is going to carefully kind of do things. Which is faster? The second one or the last one which is correct. What other opinions? They're equally, okay, great. Well I think if like you're a perfect program probably no. Because this guy has the ability to kind of generate a very unique code, parse or automaton that's only going to work for that particular string and best, right? Now here's the difference. All right. So first you have your Java 7. If you want to do fast regex don't do this, right? You don't want to use that. Kind of slow. Everything else is kind of here, right? This is a C++ library written by my friend Eric. This is the runtime edition of the regex that I just told you about. It's called FRED. All right, so it's kind of there. And then we have RE2 which is a highly optimized generic regex engine kind of written in C. And then we have V8 which is the Google JavaScript regex which actually uses specialization inside and all that good things. Which is like wicked fast and I use it like this is once. So this is like the fastest in the world, V8, right? And then there's the compile time version of the D implementation which is actually faster. So V8 is like oh my God, it's the fastest in the world. It can't do better. And then the student comes and at Google Summab of codes last year he wrote this which is actually faster than the fastest in the world. Faster than the fastest in the world. Thanks very much. Thank you.
 I think we're ready to roll.  Okay.  So I landed at Oslo Airport yesterday and I paid half of my credit limit for the taxi  after which I got here.  I was really thirsty.  So I go to the water place and then this lady who's like, you know, what would you  like?  And I say, I would like some cold sparkling water.  She's like, oh, right on.  This is awesome.  It's like choosing one of those two choices was a genial idea.  It was just perfect.  A strike of genius there.  And she gives me water like I've been like for the last six months in Sahara.  So she was incredibly courteous and nice about it.  So I can only assume that, you know, Norwegians are all nice people and that that bodes really  well for the stock.  So hello, Norway.  I'm Andre Alexanderesky.  I work for Facebook and I'm going to talk about the deep programming language.  First of all, I'm going to discuss generic programming.  So before that, in fact, let's take a quick show of hands.  How many of you actually use a language such as Java, C-sharp, C++ or derivatives?  Okay.  So it's a kind of quite targeted audience there.  This is awesome.  For that matter, so how many of you is C-sharp in particular?  Because that would be sort of the second.  Okay.  Great.  So that has quite, let's say, okay, mechanisms for generic programming.  So let's try to define it.  I'm going to go a lot by interacting with you guys.  So you feel free to not only interrupt me and ask questions, but actually interrupt me  and, you know, make points, help my talk and make it better.  So what is generic programming?  How do you define it?  You know, because C-sharp has generics.  Java has generics or at least what they call it.  So essentially, what would be generic programming as, you know, as an area of interest?  Any ideas?  Yes.  Yeah.  Yeah, it's like, let me think.  Yes.  Type?  Type as parameters.  So that would be a sort of a mechanism part of generic programming.  Let me attempt to give my own definition because it's many things to many people.  So in my opinion, it's an activity.  And it goes like this.  Well, we want to find the most general representation of a given algorithm.  Searching, linear search, binary search, ternary search, there is such a thing.  Sorting, grouping.  You know, all of the classic SQL, algebra elements, all of that good stuff.  These are activities.  Like, you know, let me take an algorithm and find its most general representation.  So what's the most general representation?  That uses a minimum amount of primitives.  Like you go in math and say, you know, the angles of a triangle sum to 180 degrees.  But that's the consequence of how many axioms.  Does anyone know how many axioms?  I remember very vaguely there's four and one is like the axiom of parallels which, of  course, I've proven in the sixth grade and my teacher was like, oh my God, Andre, what's  wrong with you?  So you define in terms of as few axioms as possible, as few primitives as possible.  Like, you know, what's the minimum amount of humanly possible data structure that can  actually sort?  Right?  So you narrow the requirements down.  Let me see if I have a laser here.  Apparently I don't.  So you make the national requirements.  Why does guarantee sort of the best sign of fan in fan out ratio you can ever find?  And by the way, big encapsulation should be a crime in 52 states and in Europe as well.  European Union, Norway, you know, everywhere.  It should be a crime.  And here's why.  Actually, I was very happy.  I was sitting in disclosure talk just earlier today and, you know, the speaker made a point  that these are constant time operations or these are log time operations and that's great  because a major issue with encapsulation of Big O is that essentially it makes it extremely  easy to get to quadratic performance which is, so quadratic on big data is essentially  it's, you know, you don't do that, right?  If you do need to do quadratic on large data, it's very explicit.  So, you know, I'm going to use a quadratic algorithm with the following, you know, with  the following improvements and sort of, you know, amendments and, you know, qualifications  and whatnot.  So it's quadratic but we kind of do it because we have to, like, you know, do like this matrix  operation and whatnot.  But sort of, you know, getting from linear to quadratic is a very easy step if you claim  that you can access the nth element of a list with a primitive, say, oh, yeah, I know how  to get to the nth element of the list.  I have to just go every step to the way and then people are going to use that as an index,  you know, loop and that's going to be a disaster.  Do you agree with this?  Big O encapsulation should not, people should not do that, right?  I'm very happy to see that happen because, like, when lists started, lists said we're  going to do everything with lists which is fine because it's going to, lists are going  to be able to represent every data structure in the universe and they omitted the comma  and what comes after, comes after which is with a blow-up in polynomial blow-up in access  complexity, you know, in time to access.  So that polynomial blow-up is actually very important.  All right.  So hope I convinced you that, you know, that's something not to do.  And you don't need to regress to handwritten code.  This is also very important so you should leave no room below your abstraction and unfortunately  my main abstractions kind of do that.  They're like, you know what, I'm just going to not, not even claim that I'm about as good  as handwritten code.  If you really want speed, you got to redo this wonderful algorithm by hand in your own  terms as opposed to reusing my abstraction.  So these are sort of, this is like, you know, a nice definition of generic program and find  the most general presentation of an algorithm and go ahead and implement it.  Then you define the appropriate data types that implement those requirements, right?  And finally, you're going to leverage the algorithm for ultimate reuse on whatever data  structures you're, you're, you're having to have.  And ultimately you're going to make a big profit out of it.  And well, so that last part depends on your entrepreneurial qualities and whatnot.  But this is in my opinion what generic program is all about.  And I would add that for me personally, this is, this is one thing I want to do.  If computer science is about algorithms, then this is it.  This is the beast needs.  This is what I want to be.  This is what I want to do.  This is what, this is kind of something that's important to my life, right?  So I want to kind of, oh, okay, so CS is about algorithms and all that good stuff.  And generic program is about finding sort of the axiomatic representation of algorithms  and structures.  And therefore, you know, I want to be there.  I want to be part of it, right?  So I would argue that this is an important thing.  Now you know the classic quote and I kind of, to change a few words in it.  I said, you know, premature optimization is the root of all evil.  I kind of changed a few words to make it like a weird, premature encapsulation is the root  of some derangement.  I didn't want to, you know, make it like all evil.  I just wanted to be more reasonable about it.  Premature encapsulation being exactly this kind of thing.  You choose to encapsulate something in a, you know, in a data structure, sort of a generic  presentation and you get to, essentially there's friction all the way.  So this is sort of a problem.  Like, whenever encapsulate there's going to be this inevitable friction and when you  compose these mechanisms together, the friction is going to just add and it's going to create  problems for the users.  Now let's work on a very simple warm-up question and it's going to be very familiar to all  of us.  It's like, yeah, you know, I want the main function that takes them to numbers or more  and it's very surprising that in this day and age, I mean, we've been doing like computing  for what?  Like, I don't know, 75 years now and it's kind of weird that people still need to discuss  a passive one and this should be a solved problem.  The simplest possible algorithms one can invent and it's kind of amazing that they still debate  like, you know, how do you do a minimum?  Oh, here's what you do and you know, don't care about that but, you know, that's going  to be inefficient and that's going to be like impractical or that's going to be, you know,  not difficult to use.  So you know, the dream mini function would be, well, let me take the, you know, minimum  of many arguments as many as I want, I want to take minimum of AB whatever.  I don't want to, you know, have a nonsensical code of minimum of one element or zero elements,  right?  I want to work for all ordered types and conversions.  So I want to take the minimum of an integer and a floating point number and what should  that give me?  The minimum of an integer and floating point number, what type should that give me back?  This is a test you're listening.  Yeah, okay.  The gentleman says floating point number.  Yeah, so you've got to kind of, you know, fall back to the most general of the two.  You can't think of a sort of inclusion polymorphism there.  How about the minimum between an assigned type and an unsigned type?  So this is going to be more interesting.  Yeah, so, you know, it kind of gets into the, into discussion already.  It sounds like we're debating here, right?  What the hell is going on here, right?  So how about the, you know, a simpler one.  The maximum between a signed type and an unsigned type.  How about that?  That's easy because the maximum is always going to be unsigned since one of the, one  of the branches is unsigned, one of the elements is unsigned.  So definitely it's going to be greater than or equal to zero and therefore I'm there,  right?  And then it comes to, you know, the whole discussion about size and all that stuff.  Like, can I represent everything representable?  So we get into this interesting notion which is, you know, which, you know, somebody who's  into dynamic typing, you know, they kind of, I lost them at the title of the slide.  It's like, yeah, I know how to define me.  It takes me one line and I don't care about types.  Like zero, I have zero concern, can take the minimum between a string and an apple and  a banana and an orange if I so want.  And it's going to give me something that I don't care much about the type.  But here we're firmly anchored in a realm where we do want to be able to do such judgments,  right?  Prior to runtime, we do want to issue such judgments.  And interestingly enough, it turns out that minimum maximum, two functions of which type  depends on the types of the input in interesting ways.  Because again, the maximum between an assign and assign is unsigned and that doesn't apply  to min.  So they're not equivalent in a sense, right?  So all of a sudden we get into a universe where weird things are happening and these  very simple primitive functions are worth talking about, right?  I can only hope by the time we all are very old and crutchety and, you know, we don't care  about like, yeah, I used to be a programmer, I don't care about it anymore.  You know, I have a pension, whatever.  So at that time, I hope there's no good, there's nobody's going to talk about this.  Because yeah, I know, you know, min, it's like there, everybody has it, everybody uses  it.  There's no more controversy surrounding it, right?  Okay.  So not to work for everybody and we want to decline incompatible types without prejudice,  right?  Let's see how we can do that.  So indeed, we have very nice and essentially like we wanted to take generic programming  C++ C sharp style and make it like absolutely trivial to use.  They should, essentially it's an embarrassment to not use it because it's so simple and it  brings you so much more generality.  It takes just a couple of characters more than writing min for ints or for floats or  for doubles.  I say well, min of left type and right type LR, they could be different as I just said.  So I'm going to take left hand side, right hand side and I'm going to do the classic  switcheroo.  But here's a question for you guys.  Why did I put RHS less than LHS and you know, usually you would put like LHS, left hand  side, less than right hand side.  Why did I swap the two arguments?  All right, who can tell me this is going to get the following.  I have here some delicious handwritten cards, invitations for one person to the Facebook  party.  It's going to be an open, you know, happy hour event.  Six to eight tonight.  Free food, free drinks, free chat.  There's no pressure like, you know, you got to apply to Facebook or whatever.  So you get at a very hip location in Oslo, which is within walking distance.  So here they told me not to tell you because then everybody's going to, you know, kind  of lynch me and destroy me and get these cards, okay?  So who answers this question is going to get one of these cards and I have a few more.  So let's see, why did I swap the order of RHS and LHS?  Because the intuition is like, minimum of A and B is, oh, is A less than B than A, otherwise  B. Okay.  Oh, come on, I'm going to go along to the party.  All right, so here's the answer.  The answer is stability because you could have types that are partially ordered.  And what I'm saying here is, well, in the case, so I'm going to swap the order of LHS  and RHS, only if RHS is positively less than LHS.  And in all other cases, including the case in which they are not ordered, I'm going to  preserve the order of returning LHS, the left-hand side.  So this is sort of a solid reason because, for example, if less than is like some string  insensitive comparison, you want to kind of, you know, keep the left guy by default and  return the right guy only if they're really ordered.  So this is sort of an interesting little detail and it's amazing, again, that we need to still  talk about this.  This invite remains open.  So I'm going to give one for each good question I get and, okay, all questions are good.  All right.  And by the way, so the other speakers told me, like, Andre, you know, Norwegian people  are really socially shy.  They don't ask questions and stuff.  So in America, I would have gotten like a million questions already.  And he's like, I'm getting some chakras, which is good.  It's a good sign.  But let's ram this up.  And by the way, to ram this up even further, I have this wonderful Facebook t-shirts, which  I'm going to get for really good answers, really good questions or really good answers  for that matter.  So let's ramp it up.  So far so good.  So we have the first min, which is like a two-liner as expected.  I mean, I wouldn't expect it to be any longer.  But the nice thing is that we have two genericity here.  The code expands to different functions depending on the input types, which means it's just  as good as you typed it by hand, right?  The counterargument there would be, well, yeah, I have too many functions now.  So it's big code.  There's a lot of bloat there.  And there are like compiler techniques to avoid that and to kind of merge a lot of instantiations  into one and stuff like that.  But for a function this short is going to be in line.  So actually typing min of A and B is going to be just as good as actually typing A less  than B, blah, blah, blah, blah, with one evaluation for A, one evaluation for B, which is perfect.  All right.  Well, let's make it, let's kind of ramp it up, take it once the further.  Let's make it work for more than two arguments, any number of arguments.  Because I can take the min of four numbers and that's entirely reasonable.  So we have this very nice variadic feature there.  Oh, look at that.  So I have this very nice variadic feature.  I say, oh, you know, min of t's dot, dot, dot, and I'm going to take a list of t's x  and that's a sort of a compiling construct.  And I'm going to do something very interesting here.  Let's say, well, during compilation static if, so during compilation if I happen to pass  more than two argument, I'm going to recurse.  Right?  So I just, you know, just classic recursion, right?  Min of the, the min of the first two and then the rest.  This dollar is like, you know, go all the way through the last element in the, this slice,  right?  So take the min of the first two and then, you know, the rest of them.  Now notice that this works only, this, this applies only if the length is strictly greater  than two, which means that x of zero is well defined, x of one is well defined, and these  guys are well defined.  Very nice.  Well, otherwise I know what to do.  I already had it on the previous slide, right?  Just take the, the min of two elements.  So well, now I can write a min of a plus b, 100, and c, or whatever I want.  And there are two interesting things, things here to note.  Number one, we're not dealing with arrays here.  And that's important because arrays already kind of bind into a specific representation,  into specific operations, into specific, specific way of doing things.  This is, these are not arrays.  These are compile time arrays, if you wish, which do not have a kind of, you know, representation  as arrays during runtime necessarily.  So these are just sort of lists of types and lists of values, which is really nice.  And I get to do operations during compilation, I get to do operations during runtime.  Some more, and this is probably even more interesting, this is not classic recursion.  So even if it says, okay, let's look at the word min, how many times we have it?  One, two, three, three times in the definition only.  But each of these three names is a different thing, which is nice because I use the same,  I use the name for the concept, not for the, you know, for the incarnation of the concept.  I will go crazy if I had to define like min one, min two or whatever, right?  So this is not recursion because each of these sort of sub, you know, sub invocations of  min is on a shorter list of arguments, right?  So I call it for, you know, the min, the big min is like, you know, I kill it for 50 arguments  if you so wish, let's say five arguments more reasonable.  But inside is going to recurse, pseudo-recurs back to minimums of smaller sizes.  And those minions are going to be different instantiation of the same thing.  And each is going to have its own address if you wish, it's going to be its own function,  right?  So all of a sudden I have this notion that I recurse during compilation, but it's not  a runtime recursion.  And that's good because it's efficient, right?  It's as if I, again, as if I kind of sit down and write the comparisons myself by hand,  right?  And I have the stack, if min were like all of them in space, that would be terrible,  right?  It would be like kind of a shameful thing to have, right?  So very nice.  All of a sudden I got min for many arguments.  Questions so far?  Yes.  Yes.  I'm sure for God's sake, what's your consideration of stability?  Haven't you forgotten to consider stability?  Okay, let's see.  What's your name?  Michael?  Michael.  Michael, let's see.  X0 greater than, no, because this is min and this is greater.  So I kind of, you know, okay, let's notice this.  So I hear you use RHS less than LHS, and here I use X of 0 greater than X of 1.  So it's the same thing just I wrote it the other way, just to confuse people like you.  All right.  You see what I'm saying?  Yeah, so essentially what I'm doing here is like, if X of 1 is definitely not a problem,  definitely less than X of 0, then I'm going to return X of 1, which is kind of the weird  thing, and in all other cases I'm going to return X of 0.  So well, I think the discussion on stability would be more interesting with a better operator  because min is kind of, you know, what you see, what you get.  Nevertheless, Michael, congratulations.  Thank you.  I'll see you tonight.  You got a date.  All right.  If you use functionality before you have two slides, I can tell you a little bit.  Uh-huh.  Ah, the news function, you deserve a card or a t-shirt.  What do you want?  It's such a good question that you deserve either what do you prefer?  You want a t-shirt?  Yeah, I'm checking a flight.  Oh, okay.  Never mind.  Okay.  So the question was, well, you have one t here, which means you kind of lose the nice,  remember like LR, like, you know, inflow or, you know, unsigned in whatever, right?  So it could be like nice things here, but here kind of losing that.  Well we're not, because t dot dot dot means a list of any types.  There's one name for it, but it's a list of any, you know, you can have inflow, double,  unsigned, char, whatever, right?  So that's nice.  So this t here stands for as many types as you want.  And whenever you refer to x of zero, t of zero, whatever, it's going to kind of instantiate  the thing with the appropriate type.  So it all holds water.  Yes?  Could you mix variables and list of variables here?  Come again?  Could you mix?  Could you mix?  You're calling, you're putting variables, right?  Because it's going to be five, a hundred, one kind of.  Right.  Could you put in a list there as well?  A list of variables?  A list of variables.  So, okay, so here in this case, t stands for a list of types.  So I can say t at zero, t at one, t at whatever.  And x stands indeed for a list of variables.  And indeed, x of zero is like one variable.  And what was the sort of the, where we're driving at?  What was the sort of ultimate?  You can recall, you can recall a function, which is all m, which was named, you know,  300 and c, right?  Yes.  What if you put a list in the function call?  What if you put a list in the function call?  In that case, if you just, if I just put like, you know, let's say min and I, min, IMP  or whatever, and just pass x into it, then it's going to be automatically expanded.  So it's going to, there are other means to encapsulate things like that and kind of keep  them together and expand them explicitly.  And actually that's kind of a cool thing to, to deal with for which reason you deserve  a card.  I actually have a hard question.  Yes.  Oh my God.  You want two cards?  You have a girlfriend?  Thank you.  You could have a list of lists, right?  Why wouldn't you just write a for loop?  If you have lists, yeah.  We could write a for loop.  This is just the same because you have a static for each.  So you have a static for loop that you can use.  I wrote this because, you know, a function from is cool and everybody's into that.  So if they say like, oh, for each one, you know, back in the 70s here.  So you know, this is, oh my God, this is awesome, you know.  So yeah, you could use a loop as well and it would be, there's a way to write a static  loop and it's going to validate, expand in compilation.  Great.  Yes.  What happens if you call min with just one argument?  What happens if you call min with just one argument?  Are you in town tonight?  You got a date.  Feel free to pick it up later, okay?  So just a second because I didn't answer that.  I gave him a card that doesn't, you know, preclude an answer.  So right now we're not good there because you can call min with like zero arguments or one  argument that's going to kind of explode.  It's not going to do well because, for example, like for, if you go with an argument, this  guy is undefined.  What the hell, right?  Yeah, you're going to get the compile time error, but it's not going to do well because  you're going to get the compile time error, but it's not going to be like, essentially  I consider it failure of defining min properly.  So you're ahead one slide or couple of slides.  Yes, question in the back.  If you're dealing with a clause language and you would probably go in a library.  Yes.  That is correct.  So the question was, the question was, well, number one, D is a compile language and presumably  going to put min in a library, which is, so you can just Google for D program language  like D lang min, you're going to find it.  And if two applications are using min, or if one application happens to use like a million  min or whatever with each with different number of arguments, which is kind of weird, it's  not going to happen, but, you know, see what I'm saying.  So there's going to be some binary code duplication there, right?  So yes, you can't put min in a dynamic library.  This min, you cannot put it in a dynamic library.  This is a sort of an interesting trade-off.  It's the other side of the trade-off, which is, well, if you want generic and if you  want kind of expansion in compilation, all that good stuff, you can kind of encapsulate  that in a DLL, if you wish, and kind of make it the same code, the same binary code available  to everybody.  So there's sort of, there's two extremes in this spectrum, and this is at the end of  the spectrum is like pretty much everything is done in compilation, and it's as if you  write the code by hand.  And there's, of course, techniques that take you to all the way to the other end, which  is, well, I want to actually write the function and lose some of the benefits, but at the  same time gain some better binary reuse.  So these things are fundamental intention.  Are you in time tonight?  Okay.  T-shirt?  Okay.  All right.  So, so far so good.  There's one more question down here.  Okay.  Up there?  Okay.  Let me know.  Yes?  Is there any way to enforce such a sense in the veritable argument?  Is there a way to enforce that T is actually all T's, you know?  Yeah.  Actually, there's a predicate called all satisfy, which is implemented in the library, and  it's, you know, all satisfied T's and or whatever.  Okay.  Awesome.  All right.  So we're at, you know, you were on slide ahead because we want to reject nonsensical  calls.  We want to say, well, I'm going to accept min of T's, only if the length of x is greater  than 1.  And here we stumble upon a very interesting feature of D, which is I can restrict statically  any function I want in any way I want with anybody predicate.  Right?  So all of a sudden I can say, well, you know, I want to take min only if the length of these  guys is 1, and if not, min just disappears.  There's no min for one argument or zero arguments.  It doesn't exist, right?  Because it kind of, you know, takes it away from the food chain, which is nice because  if I, at some point I want to define for whatever reasons my own function min that takes one  argument, I could do so because this min is not going to compete with that guy.  Right?  So this is sort of good encapsulation of modules.  So I just said that.  And you know, of course, we need to do more work, which would be sort of some sort of  interesting thing to talk about.  Like, well, I want to kind of say if x length is greater than 1 and if, so, all satisfied  T's a numeric type or it supports comparison and all that stuff, so you have to only accept  types with a valid intersection, and we only want to accept types comparable with less  than.  Right?  So you know what?  Let's actually dive into this a bit because I think it's interesting to know about.  Right?  So I'm going to throw a wall of code at you here, which is not that difficult, so bear  with me.  So the task is given a list of types, the T dot dot dot.  Let's find the common type of them all.  So let's find the sort of the least common denominator type of a list of types.  It's kind of interesting.  Like, you know, if you think of it like I'm giving a bunch of types and it's like, find  me the type that everybody converts to.  Right?  Huh.  So, well, if I have one type, then my job is very simple.  I'm just going to return the first type, the first and only type.  Otherwise, if I have more than one type, well, let me kind of do this very funny construct  here, which is type of an expression.  And the type of an expression is going to take the expression, not evaluate it because  it's all, this all happens smoke and mirrors during compilation.  This is not going to, oh, I'm running this and I'm going to evaluate that and it's going  to try that and it's not going to work.  It's going to throw or whatever and then I'm going to fail.  Now, this is all during compilations.  The compiler is like, oh, let me test the type of the conditional expression like true  one.  And if it's true, then I'm going to return the first type in it.  Otherwise, I'm going to return the second type in it.  And this anything is giving the initial value of that particular type.  So this is actually a value of type T zero and this is a value of type one.  When you do the question mark operator against two different types, what you're going to  get as the type of the whole expression, they're common type.  Because like in C sharp, if you take the, you know, condition, floating point number  and integer, you're going to get the floating point number and so on, you know, objects,  it works like, you know, actually they find C sharp finds the common ancestor, the close,  the, you know, the best common ancestor of two types, which is kind of very nice, amazing,  right?  And this is very nice.  So essentially with this operator being designed so well, right, you get to actually use it  during compilation to figure out the type, the common type of two guys.  So wow.  So at this point, I'm, well, I'm greater than one.  And I'm going to say, well, if this is actually a type that works, and I'm going to call it  you, then oh, okay, awesome, I'm going to make progress here because I'm going to recurse  to common type with you and the other types in the list.  And I'm going to alias that to common type.  And if nothing works, I'm going to say, you know what, I'm going to give up.  And the common type of these types is void, which means there's no real type that's going  to work there.  Right?  Okay.  So let's recap.  If I have one type, it's obvious.  If I have more than one type, I take the common type of two types by the magic of this type  of expression.  I give it the name you.  And if that works, I'm going to say, well, then common type is the common type of these  two types and then the trailing other types.  So recurse, right, in a way.  And yeah.  What does the?  What does the?  The bang.  The bang.  Oh, the bang is template instantiation.  So C sharp chose the, you know, angle brackets.  C plus chose the angle brackets.  There's any amount of pain that has been caused to parcel rightness and developers because  of the angle brackets.  And D went like, you know what, I'm going to instantiate with bank brands.  So that's how we roll.  Okay.  So let me note something.  Let me, this is sort of a unit test.  Well, Steadica said that the common type of in short and long is long.  So let me make, take a break here and make sort of a side point.  This is the kind of stuff that developers like, you know, as I'm, I want to get work  done in this language, right?  This is the kind of work that developers don't care about that much.  It's not typical.  Like, oh yeah, at my day job, I figure out the common type of three types.  You don't do that, right?  This is the kind of stuff that who's worried about, like who's doing this stuff?  What kind of people?  Like, who, who, who, right, what?  Compilers.  This is the kind of stuff that the compiler writer is going to be busy about.  Yeah.  During my compiler work, I need to figure out, I'm given, I mess with types all the time.  So I need to take, yeah, the common type of these two types, I know, I don't know what  it is, right?  So this is the job of a compiler writer.  And the fact that, and it's actually in the compiler, it's not in user code, so it's,  it can't be part of the target language that you're using.  So we're getting to this really weird thing.  And it's good weird, I would argue.  We're getting to this weird thing where you do type manipulation, kind of compiler grade,  if you wish, right?  Kind of, you know, compiler, I'm a compiler pro and, you know, I'm kind of doing compiler  things.  But, you know, it's not really compiler stuff because you're doing it in the target language,  in D. You're not doing it in the decompiler, which may be written in other language.  You're doing it in the library, in there, in the target language.  And you're manipulating types and kind of figuring out things about types and interest  in this introspection kind of thing.  And it's all static and it's all great.  So this opens up a lot of nice possibilities.  Like, you know, the D standard library has a bunch of, you know, traits like that.  It gives you the common type of types.  It can, here's a nice one.  For mocking.  You know what the white hole is?  White hole.  White hole is like you have an interface.  It has an influence, like it defines, like, you know, seven methods or whatnot.  And you find a white hole, which is the opposite of a black hole because it rejects everything.  So you find a class, which is an implementation of the interface and whatever you call, it's  going to throw an exception.  That's a white hole, right?  And it's used in testing and in, you know, people use it for mocking and for things like,  you know, I want to implement just one function of this interface.  I don't care if the other should throw because I don't implement them, right?  So I see not.  So I see people kind of having seen that.  And actually in Java, it's an idiom.  Like people say, oh, yeah, I went into a white hole here and people are in prayer, like,  they're like, yeah, I have a white hole here.  And in other languages and so on.  But it's all done by hand.  So it didn't even occur to people that, oh, actually that's an automatic thing to do.  Right?  And why didn't it occur?  Because it's the job of a compiler writer usually to do that kind of stuff.  Yeah, let me kind of add a feature to the language that implements this white hole thing.  Right?  However, in D, there's a white hole thing that's, that uses completely like standard  features of D that are available to all programmers.  And it's kind of very interesting that you get to implement such things, like for each  member of the class, generate a function that's going to throw an exception.  This is pretty cool, right?  So okay, parenthesis closed.  Yes?  If the contract of the interface should not throw, then you have no business throwing.  That would be a programmer error, right?  Because it shouldn't instantiate the white hole with that interface.  But it's a good point.  And in Java, it would be better off because you have the checked exceptions and all that.  So anywho, that's a good point.  Well let's use this common type guy.  So we're back to many of these whatever in the length of the list has to be greater than  one.  And then we say, well, type of the common type of T dot in it less than common type of  T dot in it is bull.  So what I do here is I take the common type of all these and I create the value from it  by means of dot in it.  So dot in it means, you know, give me the default value of that type.  Like for instance, like dot in is like zero, right?  And for characters, like, you know, all ones because that's an invalid character and that  kind of stuff.  And for floats is nan and that kind of stuff.  So but I don't care about the value here because it's all compile time stuff.  So I say, well, let me take the type of common type of all these dot in it is less than common  type of all these dot in it.  And that type is got to be bull because that's what mean asks for.  And in these two lines, I got to say the types have a common type actually in fact, it's  not void.  And the types are comparable.  And you know, there's more than two, more than one, right?  So we have this nice Boolean condition and then with the body is the same.  But this point, we got actually we got like full bore because it's the mean that, you  know, this is what I wanted in the first place, right?  So I kind of have satisfied all of my requirements.  So again, it's amazing that we need to talk about this.  The fact that different languages take so wildly different stances on this, especially  with regard to efficiency is a sort of, you know, it's a slap on the face of, you know,  our community as software developers in general because a very simple thing to do.  So I'm going to go back to this.  You're losing the?  Yeah.  Okay.  So I'm using a good point.  So the point was you're here using the less than operator and here's in the greater than  operator, right?  Oh, not here.  Sorry.  Yeah.  Wrong, wrong laser here, right?  In D, they're equivalent.  In D, using this is the same as because they're all boiled down to the same comparison.  It's a good point for which reason are in town tonight.  All right.  Congratulations.  Nice shoes.  Yes.  This is awesome.  Okay.  All right.  So, yep.  Okay.  So this is a very good question.  I'm going to repeat it in a second.  I mean, time tonight.  Okay.  So the question was, well, if I have an unsigned internet named, it's weird.  Let's say they have the same size for starters, right?  They have the same size, 32-bit or whatever, right?  32-bit, one unsigned, one unsigned.  Am I going where you want it to be?  Okay.  And then I want to take the min of the two and, you know, what's going to happen then,  right?  Well, I guess it's okay because Indy's going to be able to represent everything.  The max, okay.  So let's switch to max and now I have an unsigned and I have a signed and I take the maximum.  What's going to happen next?  Who can represent everything?  The unsigned guy is going to be able to represent everything.  So if you return the unsigned, you're in good shape already.  I think the problem comes when you try to compare an unsigned 32 to a signed 64 and  then you get into problems.  You have a common type between the unsigned and the unsigned.  Well, Indy has the following principle.  So you know, the question was like, what's the common type of signed and signed and stuff  like that.  So D follows the following principle.  It's quite similar to C, like there's like a large part of D that's similar to C and  kind of inherits in many ways.  And therefore, people, people, it's a practical thing.  People take a bunch of C code and they put it, they throw it in a D file and they hit  compile.  And then we have two traces.  We succeed to compile, oh, okay, the simpler one.  We fail to compile and that's fair because there's stuff that, you know, this is too  unsafe for us, you know, it's not our taste, not our cup of tea, too unsafe code, whatever.  That's fine.  But let's say we succeed to compile that program.  And if we succeed and if we have different behavior, that would be a disaster because  people would come like, you know, well, I took this encryption, you know, RSA algorithm,  encryption that's like, you know, 7,000 lines of C, like paste it into a D program.  It compiled what it doesn't decrypt.  It compresses, actually.  You know, something, I don't know.  That's something else.  You know, it's, whoa, that would be weird.  It's, yeah, we don't want that to happen.  However, whenever D compiles just C code, it's going to do what C does.  So it kind of has this nice preservation of semantics.  And C has a rule.  It has many, you know, several rules, but it has one simple rule which is, you know,  expression involving sign and unsigned types, unsigned kind of wins most of the time.  So actually the way I like to say the rule, you kind of ingest, is like if an unsigned  is within one mile radius of an expression, the expression is going to be unsigned.  That was a joke.  Thank you.  Awesome.  Okay.  So because of that, we have this unsigned in 32, signed in 32, unsigned is going to win.  And that can cause some problems which we eliminate through other means.  But anyhow, I think the main point here regarding this whole unsigned comparison mess is that  if you get to manipulate the types any way you want and actually mean in the D standard  library, does do that kind of, you know, semantics sensitive typing which is very interesting.  Yes?  When you have reference types, this would be called reference, just know.  When you have reference, yeah, this would be null.  Okay.  Yeah.  But that's fine because we don't evaluate this.  We just, yeah, we just look at the type.  All right.  And you know, there's all this discussion like, you know, people say it's good to have  like non-null types, right?  Types that can never be null.  And this has been a sort of a sort of thumb for D because D has null and we kind of decided  to make a library solution for it and so there's a non-null type right now which is  being discussed which is kind of interesting.  All right.  Am I supposed to be about done?  No.  Someone finished early.  That's nice.  Okay, though.  So far so good?  All right.  Well, where was I?  Okay.  So this kind of, what happened here?  Okay.  So far so good.  Okay.  Well, so it's one thing to say, well, I want to take the minimum element of like three  guys.  That's fine.  But what if I take the minimum element of an array or a stream or file or, you know,  kind of a database or whatnot.  So at this point we get, okay, so it's sort of more of the same.  I'm going to take min from a range which is some sort of collection of elements that can  be iterated through.  And this whole range thing has sort of exploded in popularity with D because it's a central  concept to D which means, you know, C++ is iterators, LISP has lists, S lists and whatnot  and D, 4D ranges are sort of the thing.  So we say, well, if I have an input range which has the first element can be compared  with less than, then I'm going to do a for each loop.  I'm going to say, yeah, for each element, just, you know, do this and do that and do  that, the other.  And that's a nice implementation of min.  And before anyone mentions it, I should tell you that, you know, you actually don't want  to write this because it's a reduced function in the standard library that's just reduced  with min, this range, and it's going to just work, right?  So this is kind of showing you from sort of almost first principles kind of thing, like,  you know, bona fide, you know, good developer code, I'm going to write a for loop and I'm  going to do that and stuff like that.  You don't want to recurse because then you have, like, you know, you've got to be careful  about making it tail recursive and all good stuff.  So this is a good example for the sake of a presentation.  Now, I say, one nice thing is, like, you know, I don't need to specify the type, it's going  to kind of take care of itself.  I say auto, type deduction for the win, right?  And what else is interesting here, I'm taking the first element, I pop the first element,  I guess this is pretty much right itself, right?  For each knows how to pop elements from a range.  So I guess, you know, if you squint a bit, because for example, I didn't define this  guy is an input range, which means he has a front, has an empty, has a pop front, that  kind of stuff.  But if you squint a bit, I'm sure you kind of get the gist of it.  Great.  And it's nice because it works over anything that can be iterated and this is, there's  no amount of overemphasizing I can do here because this sort of generality is typical  to for generic programming, which is say, yeah, I can take the, like, in Java it's very  typical, like, yeah, I know how to take the middle of an array, but that helps in nothing  in terms of taking the middle of a singly linked list.  And that in turn doesn't help me much for defining the middle of a doubly linked list  and so on.  So, you know, this kind of generality is not actually very well represented in some languages.  Here essentially this is sort of the very essence of the min algorithm, you know, the  loop over anything because anything that has these primitives can be, you know, it can  min over those, right?  So this is sort of the essence of I want to take the minimum of many elements of arbitrary  number of elements.  By the way, let me ask you this.  Do you know edit distance?  Right, okay.  Levenstein, edit, like, you know, I have two strings.  How many of these does it take to transform one to the other?  And what kind of data structures does it work on?  Like what is the minimum data structure?  You know, edit this, like, look at these guys, the dynamic programming, interviewers love  it, you know.  Erase, strings, yeah, so it's typically for strings, but more generally like a race,  right?  Yes?  Lists.  All right, so actually it's kind of very interesting that edit distance works on lists, but actually  I saw an implementation in Haskell that the author kind of didn't figure that out and  said, oh, I'm going to use a race here.  So actually edit distance work on lists.  This is the minimum you need.  You know, you don't need really a race.  So a race would be sort of a total order because they have to be contiguous on that stuff,  and you don't need random access.  You don't need random access for edit distance.  And this is the kind of job you would do as a guy who does that, who does generic programming.  You would think about these things, like, you know, what is the minimum data structure  that edit distance works on?  And this is the minimum thing that min works on because here's an interesting thing.  For min, do you need to ever look back in the range?  Do you need to kind of remember, oh, the fifth element I saw, oh, fifth element, nice.  The fifth element I saw was that, you know, this is important to me.  Is it?  No, because you kind of just walk the bridge and the bridge can kind of just sink behind  you, right?  You don't need what's behind.  So you're going to look at the current element that you don't care after you're done, you're  done.  And that's an input range.  It's a stream.  It's something that is evanescent.  It doesn't have a presence in memory.  So you can take the meaning of a very large file and it's going to work.  And that's, you know, SQL actually is big on that kind of distinction.  So this is very nice because input ranges represent exactly that notion.  It's an input range.  It doesn't have to be in memory.  It could, as the example shows, it could be an array.  I don't care because an array is better than an input range.  It has more stuff to it, so much the better.  For min, I don't care about the good stuff that array has except for the fact that I  can actually look at one element at a time.  Awesome.  Well, argmin is a very, very popular, all right.  Nothing happened.  The situation is under control.  All right.  I walk too much.  The camera folks are going to kill me.  Okay.  So argmin is sort of a popular notion for machine learning people.  Like, you know, I want to take the minimum argument, you know, the minimum index of the  index of the minimum element, the smallest element.  So that's not much more difficult.  I just have to kind of do a bit more work by kind of cashing the stuff and kind of saving  the candidate.  And you know, so my result is going to be the first element.  I'm going to cache the function and all that stuff.  What I want to emphasize here is this.  Argmin alias fun.  So alias fun is a higher order function, right?  So argmin is a higher order function because I want to say what is the minimum, you know,  argument in this range for which fun gives you the minimum, right?  So I want to say argmin of square root or whatever.  I want to, that's easy.  Argmin of tangent or argmin of whatever, right?  And at this point, I have a higher order function argmin that takes an alias and a range and  is going to use the alias to invoke the function.  And the nice thing about pass by alias is that it's extremely efficient.  So one known issue with many functional languages of today is that as you stack these nice  subtractions, map, reduce, and you know, higher order functions and stuff, they all have one  in direction each.  So by the time you have a stack of like seven, there's going to be like, you know, seven,  literally like seven in directions to get to where you want to be, right?  Pass by alias, short circles that by saying, you know, I'm going to instantiate for this  particular function, I'm going to make a separate instance for this other function.  So this is pass by alias.  And again, the usual discussion of, you know, co-generated size versus dynamic library size  and, you know, that binary code reuse that you asked, you know, these kind of caveats  still apply, of course.  So argmin, right, takes a function.  Let me see if I have an example for argmin.  Oh, thank God.  Okay, great.  So I have, well, I have a number of strings or whatever.  And I want to say, well, which string has the smallest length, which which string is  the shortest in this input?  So I have the string and I apply this lambda, which maps anything to its length.  And that gives me sort of the, what's the name, a one.  It's going to be, give me one in the end.  So with this, I kind of talked about things like, well, let's talk about, like, you know,  what do we take to write a good, a nice min function, which is completely reasonable?  And we figured out, you know, there's a lot of wanting solutions.  But then we discussed, if you do the appropriate type manipulation, it's good.  And the question is, you know, how can we put the means in the language to do such kind  of time, type manipulation?  And I talked about things like static if, which is great.  I talk about, like, pseudo recursion, which is great.  I talked about pass by alias, which is great.  Okay?  So this point here is very important.  Because I have, you know, there's a lot of talk about, like, you know, I don't care about  static languages.  I'm going to do dynamic languages and such.  And at least for my kind of workload at Facebook, you know, I think, I think this is going to  be more general because big data and, you know, that kind of stuff is going to be more  of it, not less of it in the future because the amount of data you play with and the amount  of interesting things you want to do with it is just going to grow.  And computers are not going to get any faster.  So the question is, you want to distribute the thing.  And at the same time, you know, your speed of processing is going to be proportional to  the number of machines you use, but also proportional, like, in a very direct way, like, there's a  multiplication there with the speed of each component.  And we get to this point where we're asking ourselves, like, you know, I can distribute  this thing very nice, but then it depends on the speed of each component.  And if I can't make it fast enough, it's going to hurt me.  And actually, even if I distributed it, there's a guy who says, I'm doubling the number of  machines.  Well, you're going to double the amount of power needed by those machines.  And this is the major limitation here.  I'm really digressing here, am I not?  Okay, but I think this is nice.  This is interesting to talk about, right?  So the power needed is humongous at Facebook scale.  I can't give you specific numbers, but I can say that every 1%, every 1% saved in efficiency  of the site.  And think of it that way.  One person, like, many people say everything below 10% is negligible, right?  So I'm talking about 1%, and I mean, people, like, work on a fraction of a cent, 1%.  So 1% saving of speed, like, increasing speed of the site is a very significant amount of  money in power costs of data centers alone.  And that's the case for Facebook.  It's a case for Google.  It's a case for Amazon, Yahoo, and many others.  And there's an increasing number of these companies that are going to have to use power  as they're defining means of calculating costs.  So that, for that reason, you can't afford often to say, you know what, I don't care about  this, but it can, yeah, seven directions, I'm cool with that.  You can't afford to be cool about that, quite literally, because it's going to be hot, right?  So the machines are going to get really hot, right?  All right.  If you're more interested in that kind of topic, you should come see my second talk today,  which is going to be at 3 o'clock in room 2, which is going to be about a very nice  jit architecture that we've done at Facebook.  I'm very honored to be part of that team now.  And to see how, you know, exactly what it takes and how we did it to accelerate Facebook  for 1 billion users.  The process is closed.  So now, let me kind of change gears a bit.  Because, you know, many people say, generate programming, generative programming.  And many people say, you know, there's this whole genetic programming, right?  Which is unrelated.  It's like machine learning, right?  Genetic, we don't do that.  We don't talk about that here, right?  But there's generic and there's generative.  Can you define generative for me?  Generative, generative.  Well, it's, I mean, if I didn't know anything about it, I would say, you mean, say, generate  stuff, right?  And actually, the reality is very close because it's programs that generate programs.  It's code that generates code.  Which is, oh, interesting.  Let's see.  Well, there's a connection here because generic programming very often requires specialization  of algorithm which we want to generate automatically.  And very often the specification is present in a DSL, domain specific language.  Tell me a DSL that you use every day, day to day.  Talk to me.  SQL.  SQL, awesome.  This side, didn't talk much.  Come on.  I swear it, you use every day.  Rejects.  Not everybody should use it.  I'm not saying what it should be using.  You know, rejects is everybody's using it even though they shouldn't or whatever.  So rejects, a lot of us use it, right?  Make files.  I mean, come on.  It's a DSL.  It's like, you know, and whatever, you know, whatever you use.  What do you use?  What's the latest and greatest?  And?  Is this what?  SCANs?  Who's using SCANs?  All right.  Who's using the Microsoft built-in whatever, right?  Okay.  So that's sort of, even if that guy is sort of a DSL, although you manipulate it graphically,  all right?  So very often you have this DSL notion.  I got make files.  I have rejects.  I have print tests, format specifications, you know, string templates, all that stuff.  All of that is DSL kind of stuff, right?  That's very interesting.  So what do we do about implementing these DSLs?  Well, one simple solution is like, well, we're going to kind of make the language, the host  language look like the DSL and we overload the operator, some of that good stuff.  And I don't think that's a great thing, but, you know, whatever works.  And I gave some examples already.  Some more interesting example are EBNF grammar, right?  And to define a language compiler.  Portable expression grammar, this is all EBNF on steroids.  SQL was mentioned.  And, you know, to try to force every of these, each and every of these DSLs into the same  host language would be a bit forced.  So indeed, we have a different approach which is very interesting.  We kind of stumbled upon it.  So we're going to use it with native grammar.  We're going to process the grammar in compilation and we're going to generate the code accordingly.  It's not a macro system.  It's sheer code generation from strings.  And let me start with a little insight.  So this is an absolute classic, right?  I don't need to talk about, like, how do you implement factorial in a language that has  loops?  Yes, this is how you do it.  Okay, so this is interesting, but here's the thing.  Well, I have a factor of 10 and I get an auto.  I kind of, this is like a U long.  F1 is factor of 10.  And I say static, F2 is factor of 10.  When I do that, the compiler is going to evaluate the factor during compilation.  Okay, this is how I'm going to, all of a sudden people walk up from, you know, what, what?  Okay, so this is what happens.  You have one body, but you can actually compile it and evaluate it like classic, like any  imperative language would do, but you can also, with the same core syntax, you get to  evaluate during compilation as long as you evaluate within a static context.  Huh, what the hell can we do with that?  Well, let me tell you about the second component of this ploy here.  There's a mix-in keyword that says, you know, give me a string and I'll make it into code.  So give me a string and I'll compile it, right?  It's like eval, but it's just compile time only.  So I can actually call a function and the function is going to be evaluated in compilation.  It's going to give me a string and I'm going to transform that string into code, which  is, oh, what's going on here?  So, okay, so we have two things now.  Compile time evaluation, we have mix-in.  And at this point, I got to imagine we had a big, like, oh, my God, because you get to  generate strings with compile time evaluation and you get to mix into new code.  And that's how Whitehall is implemented, by the way.  Right?  So you get to actually do real work during compilation and mean it, like, you know, real,  like, actual work.  You can create objects, you know, do stuff, right?  And then you get to generate strings during compilation and those strings, you get to  actually say compile the stuff, right?  All right.  So this is kind of a big insight.  And here's how D does bit fields.  D does have a bit field facility like C because we thought it's like, you know, too low level  to dirty our hands with it.  But it accepts a very simple mix-in function that takes type, takes name, and takes width.  And you give it more of these guys and it's going to take care of generating all the code  that takes care of the bit fields, you know, all the masking and all that, you know, rotation  and all that stuff.  And all of it is library code, it's not in the compiler.  But this is just the start.  I mean, you know, it can get really, really interesting.  I mean, consider this.  There's a work by Philip Seagal, which is, you know, he defined a grammar parser and  the code generator and you can, you have a simple expression and value to here.  Expression is like factor and, you know, more factors and then I have an ad expression,  which is plus, minus, plus, minus, factor and whatnot.  So you have this grammar syntax in a string.  That string is passed into the function called grammar, which is defined by this guy.  And the result is a string of code, which you're going to ultimately mix in into your  decode and congratulations, you got yourself a parser.  This reminds you of like Lex Yak and Antler and derivatives, right?  But it's all indeed, doesn't need any extra kind of program, right?  And it sort of holds water in a, oh, I'm kind of almost over the time here.  Sorry for not mentioning that to me.  All right.  So, very easy to kind of play with this.  But you know, my point here is that it kind of holds water because, you know, there's,  the D grammar itself can be expressed in 1000 lines and it generates actually 3000 code,  3000 lines of actual parser code that you actually, you put the grammar in D and it  kind of parses it with D and you generate D, which you compile and you compile is D.  Oh my God.  Okay.  I'm not even sure I said that correctly.  All right.  So you can think of it as a highly integrated Lex and Yak.  And last point I would like to make before I go, you know, and Jeremy and whatnot is  an actual practical result.  So there's a regex which is kind of the classic thing.  You can take a string, standard input or whatever and you make it into a regex and that's fine.  This is sort of the classic thing.  Static is CT regex and it takes the string during compilation and it does its own specialized  automaton generator in there.  Now question, which is faster?  The same string.  It's the same regex.  Which is faster?  What do you think?  So the first is I kind of bonafide classic regex that people do today.  And the second is takes a string, looks at it and generates a specialized automaton just  for that particular regex.  Yeah.  The second is going to generate its own state machine.  The first is going to generate a generic state machine which is going to work for all regex  is going to carefully kind of do things.  Which is faster?  The second one or the last one which is correct.  What other opinions?  They're equally, okay, great.  Well I think if like you're a perfect program probably no.  Because this guy has the ability to kind of generate a very unique code, parse or automaton  that's only going to work for that particular string and best, right?  Now here's the difference.  All right.  So first you have your Java 7.  If you want to do fast regex don't do this, right?  You don't want to use that.  Kind of slow.  Everything else is kind of here, right?  This is a C++ library written by my friend Eric.  This is the runtime edition of the regex that I just told you about.  It's called FRED.  All right, so it's kind of there.  And then we have RE2 which is a highly optimized generic regex engine kind of written in C.  And then we have V8 which is the Google JavaScript regex which actually uses specialization inside  and all that good things.  Which is like wicked fast and I use it like this is once.  So this is like the fastest in the world, V8, right?  And then there's the compile time version of the D implementation which is actually faster.  So V8 is like oh my God, it's the fastest in the world.  It can't do better.  And then the student comes and at Google Summab of codes last year he wrote this which is  actually faster than the fastest in the world.  Faster than the fastest in the world.  Thanks very much.  Thank you.
Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_0_59.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_60_107.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_108_1943.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_1944_2003.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_2004_4187.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_4188_4259.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_4260_10607.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_10608_10823.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_10824_11051.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_11052_11447.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_11448_12335.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_12336_13631.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_13632_19883.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_19884_22343.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_22344_26363.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_26364_31823.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_31824_31883.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_31884_32555.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_32556_32651.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_32652_34163.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_34164_34439.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_34440_34631.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_34632_42995.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_42996_45203.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_45204_50771.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_50772_50843.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_50844_51407.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_51408_55739.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_55740_55787.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_55788_56423.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_56424_59255.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_59256_60335.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_60336_60875.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_60876_67271.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_67272_67331.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_67332_67391.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_67392_67451.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_67452_67571.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_67572_69191.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_69192_71339.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_71340_72419.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_72420_72467.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_72468_76247.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_76248_79787.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_79788_85943.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_85944_86975.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_86976_89147.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_89148_89555.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_89556_89603.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_89604_89831.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_89832_89939.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_89940_90227.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_90228_90719.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_90720_92303.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_92304_94091.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_94092_94151.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_94152_94979.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_94980_96419.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_96420_96563.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_96564_97175.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97176_97223.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97224_97271.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97272_97379.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97380_97427.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97428_97475.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97476_97547.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_97548_99647.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_99648_99779.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_99780_101423.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_101424_101747.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_101748_101795.png Andrei_Alexandrescu_-_Generic_Programming_Galore_using_D-68378925_101796_101841.png