, In this segment, I want to continue looking at how Macros interact with the treatment of variables in our programming language. It turns out that semantics of Macros is different than the naive sort of macro expansion I've shown you so far, that's a good thing. It's better in situations where variables may shadow things that are in a macro. And that better semantics goes by the name of hygienic macros. That's what I'm going to show you here. So, to do this, I'm going to use a very simple example, which is a macro that doubles its argument. So, I want to emphasize first, it says, poor style. If you need something that doubles its argument, use one of these two functions you see at the top of the slide. They're both perfectly good and they are equivalent to each other. And no client can tell how you've implemented it, you just doubling and that's wonderful. But, for the sake of a short example that will fit on a slide, here are two macro versions, where the first macro replaces double of some expression x with plus x, x. The second one replaces double of some expression x with star 2 x. Now, these two macros are not equivalent to each other. We saw this sort of thing in the previous segment. If I use the first macro with this argument, something that prints hi and then returns 42, I do get the result 84. But I also print out hi twice, because I would replace double of this thing with plus of this thing and this thing and so each of them will print. Whereas, the second version will only do the printing once, because the replacement only uses this expression once. So, they're not equivalent, and we want to study that sort of thing in this segment, and even more subtle things. So, if you wanted to do something like the first one, you wanted to implement doubling as adding twice. And you wanted to use a macro and you didn't want it to print twice. Then, you should do something like this third version. What you should do is, say, well, when I have double of some expression, let's expand tha t to a let expression. Let's introduce a local variable y to hold x, so x is some expression, maybe it prints But then, y will jsut be the result of that expression, because that's how let expressions work. And then, we'll add y and y. And this is, these y's, are jsut looking up a variable that holds the result of a previous computation. So now, this macro seems to work much more like the version at star 2 x, because it only prints once. Fine, the general technique here is to use a let expression to make sure that your macro arguments are evaluated exactly once. Now, that's not always what you want. The my delay macro we did earlier we didn't necessary want to evaluate it once, we wanted to put it inside a thunk. Other times, you may want to have some of your macro arguments purposely be evaluated multiple times because that's the entire purpose of the macro. In the next segment, I'll show you something with a for loop, where there actually is some expression we want to evaluate some number of times and then, you shouldn't do this let expression either. But the technique is to use a let expression to control the number of times something is evaluated. Another thing you might think about is the order that your arguments are evaluated. So, here's an example here on the bottom that does something that you might not want. So, this defines a macro, take e1 from e2, so this is a subtraction, but in the opposite order. It says the result should be, the result of evaluating e1 and e2 and then subtracting from e2, the amount e1. Maybe this is more logical ordering of the arguments to you. But the way this is being macro expanded, we end up with minus e2, e1. And that's right for producing the right answer. But if the order of evaluating your subexpressions matters, this will evaluate e2 before e1, because we do the expansion, the result of the expansion is a function call and in Racket, function arguements are evaluated in order from left to right. That might, can the user of your macro, who doe s not know that this is the macro expansion, they just read the documentation of use this macro to take e1 from e2, might be very surprised when things are evaluated in the opposite order that they wrote them down and you can once again fix this, not shown here, with a let expression to evalute e1 and then e2 and then use those results in the subtraction. Okay. So, I'm recommending, for issues like you see on this slide, putting local variable in your macros. Those of you that have, perhaps, done a lot of programming with C and C++ macros might be really upset that I'm doing that. Because in those languages, it's usually very unwise to put local variables inside of your macros and if you ever need to do it, people end up using variable names that probably no one else would possibly use anywhere, Like, __strange_name34. So, for all of you, let me explain why, people in impoverished macro systems end up doing this and how Racket has a semantics that makes this unnecessary, you can use local variables in your macros, and everything works out fine. So, here is an example. Here is yet another version of double, it's very silly for the purpose of demonstration. So, what this does is it takes in some expression x and then it does multiply 2 and x. So, that was the easy version. But then, it also multiplies by y, where y is some local variable that holds 1. So, it seems clear that this will do the right thing, it will double its argument, it just has this unnecessary argument y. But now, here's a very strange use of the macro. It's not strange to the user, makes perfect sense that I might have some local variable y, that's 7 and then use the double macro with y. So, if I'm the user of the double macro, I'd expect this to return 14. The fact that there's some other y up in the macro definition, should be an implementation detail. But under the naive semantics, I've been kind of assuming throughout this section, that would not be what happens. If you take this double y and you replace it, as the rules up here would suggest, you would end up with let y be 1 in star 2 y, y. All I did was take the body of the macro. But wherever there is an x, I put the actual argument to the macro, which is y. This is a problem. If you evaluate this entire result, which is what you would get from that naive macro expansion, you will not get 14, you'll get 2. Somehow, the y here at the macro used got captured, got put underneath the y in the macro definition. This is the sort of thing that can happen in C or C++, this is not what happens in Racket. Racket gets this right if you have this use, exactly as you see on the slide, when you run this, you will actually get 14. This is part of what it means for your macros to be hygienic. They are clean, they keep separate the local variables in the macro from the any local variables that might be in scope where you're using the macro. The way Racket does this is it just changes the names of variables in macro definitions as necessary and we're not going to go into the details of how it does it. Just rest assured that you get 14 in Racket, you do not get the naive expansion. So, it turns out that's one of the problems that can come up. There's a second one, where you also get the wrong answer and that Racket also fixes. So, let me now show you that one. Here, I have this perfectly reasonable macro. There's nothing wrong with this macro except that you should define a function and it just takes double of sum expression x and produces star 2 x. But what if we use that somewhere, where the function star, and star is just a function, I could have shown you an example of a function named foo instead of star. What if we used this macro somewhere where star referred to something else because the built-in standard library star was shadowed? Here is such a use right here. If I call the double macro with 42 in an environment where multiplication has been shadowed by addition, then the naive expansion would be star 2 of 42 in a situation where star has actually been rebound to plus and I would get 44 instead of 84. And again, Racket does the right thing. If you have variables like star in a macro definition that are defined outside the macro definition, you look them up in the environment where the macro was defined, not in the environment where the macro was used. This is our old friend lexical scope and its applies to macro definitions in Racket, the same way it applies function definitions, then this is again, something that most macro systems including the pre-processor for C and C++ simply do not do. This is sometimes abused. This sort of dynamic scoping in those languages as a feature instead of a bug. But I would say that experience suggests that the vast majority of the time, you would rather have Racket's lexical scope and hygienic semantics, than what you get in these other systems. Okay. So, a hygienic macrosystem basically gets these two issues correct. The way it does it is for the first issue, when you have a macro definition, it secretly replaces all the local variables with other local variables and uses them consistently so they can't interfere with anything that might be used in the use of the macro. And for the second issue it basically uses lexical scope for macros the same way it does for functions. This is not what you get by naive expansion so it's actually quite a bit harder to implement Racket's module system than you would naively think. But the Racket designers and implementers were able to do that, and were able to enjoy the benefits. I would just remark in passing, these hygenic rules are not always what you want. They're just what you want the vast majority of the time. So, there's much more to Racket's module system. You could read about in the Racket reference if you're implement, interested. And they even have specific ways to indicate specific places where you don't want these hygenic rules, and they'll give you a different semantics when that's what you ask for.