 A break statement as we discussed is a special statement that will end execution of the loop in which it's contained. It'll jump execution out of a loop, like here for example in this main function, if we have this loop here, and this interloop will normally iterate five times, that's what this counter variable arranges. And so it should call do something five times, but maybe upon some condition we want to break out early instead of going through the full number of iterations of this interloop. And so when this is true, the break statement executes and execution jumps out of this interloop, the one in which the break statement is most directly contained. But be clear, we don't jump out of the outer loop, so this outer loop will continue to execute. This raises the question, well, what if we want to break out of multiple loops? We could be in like four levels deep, and we want to jump out of all four loops instead of just the inner one. Well, for that purpose, we can use what are called labels. You put a label, which is an identifier followed by colon, this here is a label, it precedes this for statement, this loop statement. And so on our break, if we specify the label Walter, then this break will jump out of not just the loop it's directly contained in, but the outer loop with the label Walter. So this break will effectively jump out of both loops, it'll jump out of two. Now of course, Walter is generally not a very sensible label for a loop. Generally, whenever I can get away with it, I'll just call it loop. If I have nothing better to call the loop label. Of course, using such a generic name may induce a name collision where you might have a complicated function with multiple labels, both of the same name. But these labels, they're occasionally very useful, but they don't come up that often. So it's kind of rare to have multiple labels. And in fact, I would say, if I ever end up needing more than one label in a function and there's a name collision I need to avoid, I really wouldn't feel bad about just calling it like loop two and loop three. Because it's going to be really rare that you ever have more than a couple loop labels in any one function. Something we could do in go pigeon is create variables of a function type. And that variable would then be a reference to a function such that you assign a function to it and then you invoke that reference as if it were a function and that has the effect of calling the function with whatever the variable currently references. And so here we're creating a variable f whose type is a function taking an int in a string as parameters and returning a Boolean. And this is how we denote it in go pigeon. You wrote f in and a little brackets. But here it looks basically just like the signature of a function will need to find it, except there's no name of the function and you don't have names of the parameters. And so having to find this variable f, we can then assign foo to it because foo is a function which matches the signature. It has an int and string parameter in that order and it returns a Boolean. And so if we invoke f like a function, f currently references foo. So this call here to f is the same as this call here to foo. Be clear though and we saw this in go pigeon. Functions with different signatures have different types. So here for example foo and bar have different signatures of different type functions because they have the same parameter types in the same order. But then foo returns a Boolean an int and bar returns nothing. And so now having to find f to be a function taking an int in a string and returning a Boolean an int, we can assign foo to it, that's valid. But if we assign bar to f, that's a compile error because bar is the wrong kind of function. Here in Maine, we have a cat variable c and another cat variable c2. And we have this variable f whose type is a function taking a float 32 and returning a float 32 and this expression c not eat. Eat is a method of cat, but we're not calling the method. Instead, what this expression returns is a function. It returns the function which is the method code. But it does so in a special way because when you call a method, there's supposed to be a receiver. And so what f is being assigned is not just a reference to the method eat, but also to the value that's going to be passed to the receiver. In this case, c here. So when we call f with the value of 0.4, 0.4 is passed to food to the float 32 parameter. And this c is passed to the receiver of eat, also called c. And so we get back 15.6 because that's 15.2 plus 0.4 gets us 15.6. But then when we take c2 and access the method eat without calling it, we get back again, again the same method represented as a function. But now the implicit receiver, the bound receiver is c2, not c. And so when we call f in this case with the argument 0.4, that's this weight value, 8.4 plus 0.4 giving us 8.8. So yes, we can treat methods like values like we can with functions. But when we use a syntax, when we refer to the method, it is bound to the receiver. And when we access methods, much like when we call them, if say the method is expecting a pointer receiver, but our value is a non pointer, well then we could get the reference explicitly as we do here, or we could leave it implicit. We could just write c in this case, and it would be the same deal. And likewise, if the method were expecting a non pointer, but we had a pointer, like say here the cat were a pointer, well then explicitly we could do the dereference like so, or we could just leave it implicit and it'll be done for us. So that's consistent with the implicit referencing and dereferencing, which happens when we call methods. Now sometimes you might want to reference to a method with no bound value. You want to get a reference to a function where you pass the receiver value explicitly. And you can get this with what are called method expressions. Here for example, say our cat has an eat method, again taking a float 32, but now we're turning an int. And we want to store a reference to this method in a variable where we have to pass in a cat explicitly. And the syntax for that looks like a method value, but in a method expression, the thing before the dot is the type name itself. So because eat is a method of cat, we write cat.eat. And that gives us back a function stored in foo here, which is expecting a cat as its first argument, then a float 32 and then an int. So you get back a function where what is the receiver in the method is now the first parameter of the function. And then likewise here, we're assigning to bar a function which is the method eat, but the first parameter is a pointer to cat. And because the dot operator has a higher precedence than asterisk, we have to put the type name in parems for the syntax. And so now, given some cat, if I want to call foo, it's expecting a non pointer cat as its first argument and then some float 32 value. And when we call bar, it's expecting a pointer. And there's no magic here where non pointers are automatically referenced and non pointers automatically dereferenced. This is not a method call, it's a regular function call, and you have to be explicit about passing the right type of thing. So we get compilers down here when you're trying to call foo with a pointer to cat and bar with a non pointer because they're expecting the opposites. Now, sometimes when working with functions, it would be convenient if instead of having to write the function as its own separate thing at the top level of code as we do here and write the function foo, it'd be nice instead where that function is used, particularly if it's used in just one place, if you can just define the function in that one place. And we can do that with what's called an anonymous function. An anonymous function is a function which is written as an expression inside another function. And so here, this syntax, which looks exactly like a function that we defined outside, except it doesn't have any name. There's no name for this function which is being created and then assigned to F. The syntax is otherwise just like a function definition except it's considered an expression. It's a thing which returns a value. So in fact, if I put parentheses around the thing, that would still be valid because you can take any expression and put parentheses around it without changing it. But we don't actually need the parentheses in this case to be clear. And of course, in this case, we don't need to make the declaration of F and its first assignment separate. We can combine that into one statement and we can in fact use the colon equals syntax. And so now we can get rid of this line and that is equivalent. We're creating a variable F, signing it this new function, this anonymous function. And this is a function which has a single parameter which is an int and it returns an int and its body in these curly braces has a single statement. Understand that an anonymous function can have as many statements as you like just like a top level function. So we could put any number of statements in here like say pretty not high. One kind of scenario where anonymous functions come in handy is something like this where we're dealing with this function process which itself takes a function as one of its arguments. Process is a so-called higher order function because it takes in another function as argument. And what happens in this program is we create a variable X which is a slice of ints with the values three, two, four, negative 10 and eight. And we're calling process passing in the slice of ints X and then also adder which is this function defined here which has the appropriate signature which process is expecting. It's expecting for its parameter F a function taking an int and returning an int. And then what happens in process is we look through all the ints in the slice of ints and for each int we are passing it to F and the value returned the int returned we're then assigning in its place. So we're going through this slice of ints and overwriting that value with the result of feeding it through this function F. And in this case the function we passed a process is called adder which takes the value pass in and adds five. And then after calling process if we print out the values of the slice we get eight, two, that's a mistake we should be adding five to it, so seven. So three plus five is eight, two plus five is seven, four plus five is nine, negative 10 plus five is negative five and eight plus five is 13. So that code is all fine except you might find a bit bothersome if this function adder is not used anywhere else in code. If the only place we're using adder in our program is to pass it here to process it'd be nice if we could just create the function right here in the call and that's what we can do with an anonymous function. This code here is entirely the same except instead of having an adder function at the top level of code instead we just wrote the function here as an anonymous function directly in the call to process. And it's a little tricky to get used to looking at the syntax because when you start putting anonymous functions in your code and people prefer different styles about how exactly to format the code is how I would do it. So this is a call to process starting here and here's the end per end closing that call. Here's the first argument, the slice X and then here's the anonymous function which we're passing to F. So that's one reason to use an anonymous function. It's sometimes more convenient and in some cases arguably makes the code look a little cleaner. Another reason to use anonymous functions is that an anonymous function has access to the local variables of the function call in which it is created. So here's say in this function main. Main has four local variables, A, B, bar and Z and the bar is being assigned this anonymous function and this anonymous function here if it likes can access the variables A and B because A and B are local variables of the enclosing function that exists when this function itself is created. We can access bar, we can access Z because they're declared down below. If we wanted to have access to them in the anonymous function we'd have to declare them ahead of time before the function is created. But here we can access A and B and so inside the anonymous function it has its own local variable X declared here and we're taking the value of X and adding A to it. But because this anonymous function doesn't have its own A the A we're adding to is this A out here in the enclosing scope. If we gave the anonymous function its own A variable like here well then if we use the name A inside the anonymous function it would refer to this one the one that which belongs to the function itself but if we remove that name collision now we can access the variable A of the enclosing function. And so down here when we call bar it's adding X to the value A and we get back five because the current value of A at the time of this call to bar is three. And in fact if we were now to modify this to say seven and then call bar again well now when bar is called the variable A which this function refers to now is the value seven and we add two to it so this would get us back nine. So be very clear anonymous functions have access to not just the values of the variables at the time the function is created it has access to the variables themselves. When this anonymous function was created A had the value three but subsequently when we modified the value of A that change was reflected in bar because bar is referring to the actual variable A not just its value. And in fact inside anonymous functions we can even modify the value of outer variables. So here we're gonna just take A and increment it by three and so now here we'll get rid of this assignment. Now in this first call to bar the value of A is incremented from three to six add two to that we get eight and then when we call bar again the value of A is incremented from six to nine add two and we get 11. So an anonymous function can both read and modify the local variables of functions which enclose it. This phenomenon where an anonymous function retains access to local variables of the function or functions which enclose it. This is called closure and I say functions plural because it's possible that our anonymous function could be inside another anonymous function which is inside another anonymous function. You can have more than one level deep of nested functions and an anonymous function can see the variables of all the functions which enclose it. So if you have an anonymous function of five levels deep that innermost nested function can see all four of the enclosing scopes above it, et cetera. Anyway, the very important thing to understand about these closures is that those retained variables are particular to a certain call. So to demonstrate here we have this function foo which is returning a function taking nothing and returning an int. That's what this means is the name of the function here's this parameter as it takes nothing in and it's returning a function which itself takes nothing and returns an int. And inside this function foo we have a variable a which is an int variable with a value two. And what the function returns is here the synonymous function which is taking a of the enclosing scope and incrementing this value by three and then returning that value. And so every time foo is called we get back a function which has closure over the local variable a of that call. Separate calls to foo have their own local variable a. So the function returned every time has the same code in that sense is the same function but they're different closures. They have different retained variables a. So down here in Maine we have variables x and y which store a function taking nothing and returning an int. And we're calling foo twice and the first time we call foo we store that in x the second time we call foo we store the returned function in y. Both x and y are referencing functions with the same code that do the same thing except they have different closures. They have different variables a which they're retaining. And so if I call x the first time it's returning the value of a after incrementing it by three. So it starts out with value two and the first time we call x two is incremented to five and that's what's returned. Second time we call x a is incremented to eight and that's what's returned. Third time we call x a of x is incremented to 11 and that's what's returned. But now when we call y after calling x three times y has its own separate a which still before this first call to y is the value two. And so the first time we call y its a is incremented from two to five and that's what's returned. Next time we call y it's incremented to eight and the third time we call y it's incremented 11. So again the a of x and y are totally independent. Same code and in that sense the same function except x and y are referencing functions with different closures because they were created in different calls to foo. And so just continuing on here after calling y three times if we call x again well last value of a and x was 11 that gets incremented to 14. Call x one more time it gets incremented to 17. Then if we call y the last value of a for y was 11 back up here now it's been incremented to 14. Call one more time it gets incremented to 17. So that's what we call closure. It's a function with reference to a particular context of retained variables. And it's possible that we sometimes might have references to the same function code but those functions have different closures. So how might closures be useful? Here's one example. Say in our process example the amount that we increment the values by we want to be determined by something which the user inputs. So this prompt int function is going to add console prompt the user to enter an integer and it's gonna return that integer value which will be stored then in val. And now this anonymous function we're passing the process thanks to closures it can use this variable val that's created out here. It retains access to that variable. And so when we process the slice of ints x we're incrementing it by whatever value the user entered at console. And without closures we'd have to find another solution and I don't know what you do maybe have a global variable whatever the solution is it wouldn't be nearly as convenient. Last thing about closures it's important to keep in mind that because multiple anonymous functions can be created in a single function call like saying this call to main here we're creating both a function stored in F and an anonymous function stored in G both of those functions here have the same closure they're both referencing the same variable A. So when I call F here which is incrementing the value of A by five and then I call G which increments the value of A by two they're both incrementing the same variable. So this call to F here is incrementing this A to eight and this call to G is incrementing it from eight to 10 and now when I print out A it's a value of 10.