 Hello, this is going to be a quick rundown of my educational programming language, which I call pigeon, which is actually two separate programming languages, dynamic pigeon and static pigeon. But here I'm just going to talk about dynamic pigeon and cover static pigeon in some later video. And first things first, what we need to do in any programming language is deal with basic data types like numbers, very obvious kind of piece of data. And what you want to do with numbers is you want to be able to perform arithmetic, of course, you want to be able to add them, subtract them, multiply and divide them. And the way that's conventionally notated, as you learned in school, surely, is with symbols like plus and minus. And this would mean multiplication, this would mean division. And you put the operator in between. But in pigeon, we use a different style of notation, we put our operations, we write them all in parentheses. So the parentheses are non optional. And then instead of having symbol names like plus sign, we have words. So ADD is addition, sub is subtraction, moles, multiplication div is division. And the operator, the thing which denotes what operation we're performing that that goes first. And then the operands, the input values were operating upon those are just separated by spaces after the operator. So this is adding together three and five. This is multiplying two and negative 11.77. This is subtracting from 10, the value four, et cetera. There are various reasons for this notation. One is that as you'll see later, we're going to introduce more operators that are not familiar from mathematics. And so it's easier to understand if you don't have to deal with funny symbols, if you can just deal with words. And also it works out to be a more uniform style of notation as you'll see down the line. Another advantage of this notation style is that when you add multiple numbers together, or you're not limited to just two operands. So here, you can have four operands to one out operation, there's really no limit to how many operands you can have for one operation. So it's just slightly more convenient. So instead of having to write a bunch of plus signs in between, you can just have one operator, one operation. And be very clear, operations return values. And those values then can be used as the inputs as the operands of other operations. So here the ad operation, one of its operands is itself a multiplication operation. And the way evaluation works, the way this is executed is the inside stuff is done first, because we need to get the value returned from this, so that we can add it together with these other numbers. So this of course multiplies four times three and gives us 12. So it's adding together 8.2, 12, negative five and 20. In addition to numbers, another basic kind of data is what we call Boolean values, they're called true and false. It's just those two distinct values. We have various operators that work on Boolean values and return Boolean values. So the Equality operator, you can give it two or more values of any kind, and it'll return true, if all of the values are equal to each other. So in this case, of course, five is equal to five, so we get back true. And then is five equal to seven? No, in this case, they're not equal. So we get back false. Then we have LT and GT standing for less than and greater than. This is a test of whether this of course only works in numbers. And the left has to be less than the right for us to get back to otherwise we get back false. So in this case, this is true. This is false five is not greater than seven LT and GT and that's less than or equal or greater than equal. And so LT five seven, that's still true five is less than seven. But LT seven seven that's is seven less than or equal to seven. Yes, it is because it's equal. So that's true. We also have operators like and and or the and operator takes in any number of Boolean operands, well, two are more Boolean operands. And if they are all true, then we get back true. So this top example, we get back true because they're all true. But if any one of them is false, then we get back false. So here's a slightly more realistic example. If we do a test of nine equal nine, is that true? Yes, this five equals seven false. So this and operation one of the inputs is true one is false. And because they're not all true, then we get back false. The or operator is sort of the opposite in a sense. It's looking for you only get you get false when all the operands are false. And you get true when any of the operands are true. So in this example, because they're not all false, then we get back true. So the same example has been above except with the or operator. Again, this is true. This is false. So one of the operands here to or is true, and we get back true. And then we have the not operator, which just gets back the opposite truth value. So given the value true, we get back false. Given the value of false, we get back true. A variable in programming refers to a symbolic name, which represents a location memory that stores a value. So we can store values and variables. This is really not the same thing as variables and mathematics, because in mathematics, you think of a variable you're thinking of like an equation of y equals 2x. And that's not really a variable in the same sense, because they're y and x, their values depend on each other. And also at any one time that in that equation, x in the sense represents all possible values, just in relation to this other thing, why? So it's really very different. A variable in code is something which at any moment in time, it just has one value. Anyway, so the way we create variables in pigeon is with a locals statement, where you just write locals, and then you list names for variables, any number of variables, one or more. So we're creating Ted, Bob and Amy. And then to store a value in a variable, to assign a value to a variable, as we say, we have the as statement as an assignment. And so you specify the name of the variable was assigning to and then the value. So this is assigning to Ted, the value three. This is assigning to Amy, the value true, Bob is being assigned negative 7.5. And then here, Ted is being assigned the result of this operation, which is, is Bob equal to four, and currently Bob is negative 7.5. So at this moment, these Bob is not equal to four. So this returns false. And that's what Ted is assigned. And then this operation is negative 7.5 equal to no add 7.5 to two, that gets us negative 5.5. So Amy is assigned the value negative 5.5. When you create a variable, initially has the value nil, which is a special value that just represents nothing. So here in this example, Ted and Bob, they start out nil. And then we assign four to Ted. And then when we assign Bob to Ted, well, Bob still currently has the value nil, we haven't assigned anything to it yet. So it has a value nil. And now Ted also will have the value nil. Here we have a string. And a string is just a piece of text. It's a sequence of characters, another kind of piece of data. And so in this case, the strings are denoted in double quote marks. And the characters in between are the characters that make up the string. So this is the string with the data capital H, lowercase i space, space is a kind of character, comma, lowercase w, or ld period. So that's 10 characters. Again, be clear that the double quote marks are not part of the string itself. They're just used to denote where the string begins and ends. And there are a few operators that deal with strings. We'll just look at one right now. There's a concat operator, which takes two or more strings, and concatenates them together, meaning it creates a new string, it returns a new string, which has all the characters from this one, this first string, and then all the characters from this next one. So we get back a single string with the characters time warp, all those one string. And so that's what's being assigned to Kim here. So far, the operations we've been doing, simply just create new values that sit in memory, but they're not anything that the user of the computer interacts with, they're not stored on disk anywhere, they're just sitting in the memory. And as soon as a program shuts down, like they'll just totally disappear. So ultimately, your program has to do what we call input output IO, it has to interact with things outside of the program outside of memory. And pigeon, because it's an educational language has very limited facilities for doing that real language let you do most anything that a computer can do. But here, we're keeping it very simple. And so we just have, well, we'll see a couple operators later. But here's the most essential print, which will take a value of any kind and display it as text on the screen. So here, this is printing out the value three. There's also print line, which is a minor variation, which just prints out the value and then adds a new line after. So it's like, it's like hitting carriage return when you're typing, it's going down to the next line effectively. So what we print afterwards will be on the next line. We're printing the string high, you're printing print lining, the value of Anya, which is currently the string high world. And then print line here, here, there are two operands for print line. And when it prints them out to print out with a space in between the operands, if you don't want that, you can always concatenate together your, your stuff together into one string first and then print that out, or you can have separate print, print operations. So a very essential thing we want to be able to do in code is to branch to have our code not necessarily just go top to bottom in the same sequence every single time we want to make decisions and either do something or skip over that thing. And that's what an if statement does. And if statement begins with the word if it has a condition, and then it has a body, which is one or more other statements inside the F. And the way we denote that in pigeon is that these statements, you know, they're part of the body of the F because they are indented by four spaces after the F. So this is the first thing of the body. This is the second. And here's the condition. This last thing here is not part of the first statement after the F it's not part of the F and you know that because it's indentations lined up with the if it's not indented in. Okay, so how this works is that when the if statement is reached in execution, its condition is evaluated. And if it returns true, then the body of the if is executed. Otherwise, if the condition returns false, then the body of the of the if is skipped over. So if we get here in execution, this condition is evaluated is x equal to seven, assume x has some variable that's been created already and has some value. Well, if it has the value seven, then this condition will be true and we're going to print out high, then we're going to print out yo, and then we're going to print out by. However, if we reach the if statement and x is some value other than seven, then this condition will be false. And so we're going to skip over printing out high and yo and instead just skip straight to printing by. So it's a body of code that's either executed or skipped over that's how an if works. Okay. And because ifs themselves are a kind of statement, well, a body is something that's just one or more other statements. So you're going to have ifs within other ifs. So here, the second statement inside the outer if is itself an if with the condition of y equals of y and 11. And then it prints out yo if y equals 11. And then it just continues on after this executes or doesn't execution just continues here, right? A very common scenario is that you want to have two chunks of code, which are mutually exclusive, meaning you either do one or you do the other. But you're never doing both, you're always doing one, never both. And you can logically arrange that by just having two if statements one after the other, where the condition of the second is the logical inverse of the first. So if your first condition is x equals seven, well, you want to do something maybe different for all cases where x is not equal seven, then you just take that same condition and surround it and not. And so in effect, so what's going to happen here is that if well x is going to be seven, then you're going to execute this and then this is going to be false and we'll skip over the second if body. But if x is not equal seven, then we skip over the body of the first if this will be true, and this will execute the body of the second if we'll execute. So we have a mutually exclusive arrangement here. Now, this is common enough that we want something less verbose than having to repeat the condition like this, it's kind of awkward. I mean, one solution is you could create a variable and assign the value of that expression to the variable and just use that variable itself as a condition. This is legal doesn't have to be an operation here could just be a variable. So this is maybe slightly neater, especially if this expression were really complicated. But what we normally do instead is there's a option with if statements to have a so called else clause. And the else clause follows the if immediately, and has its own body. And this is logically the same as a code we just saw it's just if this condition is true, then this body is executed. Otherwise, if this condition is false, then this body is executed instead. It's always one or the other, never both. Now, sometimes you want more than two mutually exclusive cases, you only ever want one of them to execute and you always want one of them to execute. So we can arrange that with putting if else is inside the else's of other ifs. So here, this may be a little much to follow, but I'll walk you through it. So first off, what's going to happen is, we're going to check Well, is x equal to seven? In that case, we're going to print high. Otherwise, we're going to jump down here and if x is equal to nine, we're going to print yo, and we're done. But if that's not true, if x is not equal to nine, we come down here and test if x is equal to 11. And if that's true, we print aloha. Otherwise, if that's not true, we print later. So these four things we want to do are mutually exclusive. And depending upon the value of x, we, we do one of four things, and always just one of the four things we that we never do this thing and also this thing, right? It's, they're all mutually exclusive. Well, this works. But as you might see here, this kind of verbose, and this is a common enough thing to want to do, that there's another convenience with ifs called an elif clause, where the if here has two elif clauses, and each elif has its own body, and has its own condition. And the way this works is the if conditions tested first, if it's true, we execute that and skip over everything else. Otherwise, if this condition is true, we'll execute this and skip over everything else. If if x is not equal to nine, we're going to come down here and test if this is true. And if so, print this and skip over everything else. And an event that none of those conditions are true, the conditions are tested top the bottom. And if none of them are true, then this else clause will execute. And again, we still have four mutually exclusive cases, one of these four cases will run always one of them, never more than one, always just one. And be clear that the else clause is optional. So you can have an if with elif clauses and not have any else. So in a sense, these are still mutually exclusive, but it's possible that none of them are going to execute in this case, because there's no else the else access like sort of a default where if none of the conditions are true, then the last thing that under the else, that's going to run by default in a sense. Another very essential thing we want to be able to do in code is to have chunks of code which repeat for some number of times. That's what we call a loop. And the way we write loops in pigeon is with a while statement. And while statements actually are almost exactly like if statements, except for one major difference. Well, they don't have any elif clauses or else clauses, but they're otherwise there's one major difference, which is that here, we have the condition of the while, and we have the body. And if this condition is true, then the body will execute. But after the body executes, execution jumps back up to the condition and tests it again. And if this condition is true again, then we're going to run the body one again. And after running the body, we again jump every time we jump back and test this condition again. So the while loop, the conditional keep being tested until eventually tests false and only then do we skip over the body and then continue on with whatever's after the while loop. So in this example, we have this variable, what we commonly call a counter variable, because we're using it to count through the iterations of the loop through the runs of the loop where it's going to increase by one each time. And we have it start out with a value zero. And then our condition is going to be testing if x is less than three. And first time around, well, yes, zero is less than three. So this is going to be true. We're going to print out high. And what we're doing here is we're be clear, this is an assignment to x where this expression is evaluated first, it's taking the value of x whatever it currently is adding one, and then assigning the result of that to x. So this is all effectively incrementing the value of x by one increasing this value by one. So this is going to increase x to one. And we come back up here is one less than three. Yes, it is also less than three. And so we're going to print high again, come down here increment x to two, come back up here is to two less than three. Yes, it is print high, come down here increment two to three. And is three less than three? No, it is not. It's equal to three, but it's not less than three. And so then we're going to skip over the body and continue execution. So this loop effectively is going to run three times. That's what we've arranged. Here's basically the same code with slight variation. Instead of x starting at zero, it starts at two. And now our condition is x less than seven. And we're going to print out the value of x. So what this code does effectively is first time through x is going to have the value two, then it's going to have the value three next time through next, then four, then five, and then six. And then in the last run through, we print out six and add one to six, we get seven. When we test the condition is seven less than seven, that's not true. And so execution continues past the while. So this loop effectively runs five times. As a tiny little convenience, because incrementing a number by one is something done commonly enough, we have another operator called Inc, which just takes the value and adds one to it. So this is slightly more compact this way. But even further, as a further convenience, because loops of this style are so common where we have a counter variable and we're incrementing the counter variable at the end. That's so common that we have more compact way of expressing that there's what we call a foreign loop, where you specify a variable, and you have a starting value for the variable, and then the end value. And each time it'll increment the value of x. And as long as the value of x is less than the end value, it will keep iterating. So this code is effectively equivalent to what we just saw above. x will start out with value two. And the last time through, it'll have the value six. And sometimes you for various reasons, you might want to have a counter that counts downwards instead of increments up. So we also have four deck. Deck is in decrement to subtract one. And so this code looks exactly the same, except now the starting variable, starting value, of course, should be greater than the end value. And so x will start with seven, go down to six, then five, then four, and then three. And then last time through, it increments, decrements three to two. Two is not greater than two. And so the loop ends. So it'll be clearer for me can four deck. They're not essential things. We don't need them. But they are convenient for a very common kind of loop. Otherwise, the code would get unnecessarily verbose in some cases. So far, we've dealt with operators, which are things provided for us by the language, we don't define them, they come predefined. A function, in a sense, is like an operator which we are defining in code. And so the way we do that is you have the word funk, special word funk, you specify the name of the function. And you write a body for the function. So this function, George, is something when used, it's going to print high and it's going to print yo. And that's all it does in this case. And the way that we run this body of code elsewhere in our program is we use George, the name George like it's an operator. And in this case, it looks a little funny because George doesn't take any inputs. We'll see functions that can take inputs in a minute. But for now, George is a function taking no inputs. So you just have it in parentheses. And this is calling the function. So this line is calling George. And we call it again. So this code effectively is going to print high, and then print yo. One way to think of functions is it's like you have this chunk of code. And you want to give a symbolic name such that elsewhere in code, you can just refer to it by name to run that chunk of code. That's effectively what we've done here. As of yet, the code we've seen is not proper pigeon code because there's one central thing missing. All of our code has to go in functions. And there's one special function that we have to create called main, because this is where execution of our program begins. Our program kicks off by calling the function called main. And so here this is a complete pigeon program where our function main calls George twice. And George is defined as being a function that prints high and prints yo. So this program would run in its entirety is going to print high, then yo, and high, then yo, and then it quits, it's done. As soon as execution finishes with main, that's when our program ends. Another thing I glossed over is that we use the local statement to create variables. But the rule is that local statements can only go as the first thing inside a function. If a function wants to have variables, the local statement has to be the first statement inside. So here George has a single variable y, and then main has a single variable x. And a very important thing to understand is the reason they're called locals is because they are local to the function in which they are created. The variable y here doesn't exist in main and vice versa. This variable x doesn't exist in George just is not accessible there doesn't exist at all. And so down here if we tried to assign to why well the composite look at this and say hey inside main there is no there's no variable called why we have an x but no y. Now here George has a variable x but then main also has a variable x and the really important thing to understand here is that x of George and x of main are totally distinct they're just separate variables that happened of the same name. Again local variables belong entirely to the function in which they're created they don't exist in the other functions. And so here when I'm assigning to x I'm assigning to x of George when I'm printing x I'm assigning this x of George and then down in main when I signed to x here it's this x of main it has nothing to do with this x up here in George they're just totally separate they just happen to have the same name. Functions I did say are like operators that you yourself are defining and operators as we've seen them so far they return values right well how do we return the value from our function we do it with a return statement so here function George is a function which prints out the value high the string high and then it returns the value 9 this is the return statement and here's its value of what's being returned and so now when we call George we can use it like a value and so this function is going to print out high and then return 9 and then 9 will be assigned to x and be clear that functions actually always return values whether we have a turn statement or not if execution gets to the bottom of the body of a function when the function is called well by default is going to return nil so this is sort of like just implicitly having at the end a statement that says return nil so here when we call George the resulting value nil is assigned to x. Lastly if functions are truly going to be like operations then they need to be able to take input values and the way that's done is that you give your function so called parameter variables here George has parameter variable cat and one called dog and what this means is that when we call George we need to provide values for each one of the parameters so this is the the argument value as we say for for cat and then three is the argument for dog and so in this call here cat starts off with the value for dog starts out with a value of three for this particular call to George a second a separate call to George could have different input values but in this case it's four and three and so in this case first thing will happen what they're going to take the value of cat which is four add two to it so we get six and assign that to cat be clear that cat and dog their variables but what's special about them is how they get their initial value they get their initial value from the arguments passed in the call so anyway cat will now have the value six and we're going to multiply cat and dog which will be let's see six and three gets us 18 so this function this this particular call to George then is going to return 18 so down here x is being assigned the value of 18 and here we're trying to call George again and we can provide different arguments but in this case we're going to get an error because we provided one two few arguments George is defined to have two parameters so it's expecting two inputs and if we just provide one input the compiler well the compiler doesn't detect it but when the code runs it detects oh you have two few arguments here and that's an error a global variable is a variable that exists throughout the whole program and for the full run of the program to so you can access the variable in any function and the variable exists at the very start of the program and exists through the whole lifetime of the program it exists until the program ends so here this is creating a global variable called x with the value six this is the initial value and then when a program kicks off it's first off well main doesn't have its own x so this must be x the global variable so this is printing out x the global variable six we're then assigning a new value 10 we're then calling Lisa and Lisa Lisa also doesn't have its own variable x so this is the global x being used and assigned here so we're taking whatever the value is currently adding four and assigning that to x so after this call if we print x again in main it now has the value 14 here though we've changed things because now Lisa has its own x and that's a so-called name collision between this local x and the global x they're they're separate variables that have the same name and what this means effectively is in Lisa is that we can't refer to the global x at all so when we add x here to four and assign x that's the parameter x of Lisa and that's what the value being returned here is the value of the parameter x not the global so the x is here or not the global at all whereas down here in Maine Maine doesn't have its own x and so x is the global variable so far we've dealt with numbers booleans and strings now we're going to introduce lists which is another kind of data a list as the implies is something which is itself not a singular value it's a list that can contain other values so you can have a list of numbers a list of strings a list of booleans or a list of some mix of numbers and strings they don't have to be the same type in a single list and in fact lists because they themselves are values you can have lists that include other lists as we'll see so the way you create a list is with the list operator so in this function main we're creating three variables x 1 z first to x we're signing an empty list into y we're assigning a list with three values the number 652 and high a string high and then to z we're signing a list with a single value yo and we have the len operator which will give in a list return the number of items in the list so x is the length of zero y is the length of three and z currently has a length one and then we can access the elements of a list with the get operator and so you put the the list first here the y is a variable storing a list and then the index of the item in the list and this is a bit strange but the items of a list are known by the position so far so good but the first item list is known to be index zero not one so the first thing is index zero the second is index one and the third is index two etc so if we get why zero we're getting the first item out of this list why and the first value there is 600 get why one because it's back 52 because that's the second item in the list and get why two is high be the string high because that's a third item in the list and then here we're just getting the first item out of the list see which is the string yo and we can also modify the values in a list we can change them so initially this list had these values 652 and high but we were changing we're setting what the value at the first index is whatever it was previously now it's going to be the string by and then so it's like a signing in a sense but you're signing to the slots of a list not to a variable and then here if now if we get why zero having just set why zero we get back by instead of 600 which is what it previously had and you can print out lists like in you can print any other value and it's going to print out these values in order a very important thing to understand about lists is that you create a list it exists at one place in memory and then when you sign it to a variable what that variable is storing is not really the list itself but the address of the list in fact this is true with all kinds of data in pigeon is when you store a value in a variable what's really being stored is the address but the thing about lists is that we can mutate them we can modify what a list looks like and so this has special consequences here if we have two variable two variables X and Y if you create this list and assign it to X well X is now referencing this list this list exists somewhere in memory it has three items and then if we take the value of X and assign it to Y what Y is now storing is that same address it's referencing the very same list it's not a copy of the list it's the actual same list and so if I then set index one of the list Y to now be yo and I get index one of X well Y and X are referencing the same list and so if I modify the list through Y I'm going to see the same change through X because after this now the index one of that list is yo not what it was previously which was high one more operator that works on lists is the append operator which given a list and a value appends that value to the end of the list and increases the size of the list in the process so here we create a list X and it starts out with three values and so if we get Len X we would get the value three but then if we append to X the value nine well now the length is four and if we append another value the string yo then the length is now five and so now we can get a value at index four which would be the fifth element the list and we would get yo so you can actually grow the sizes of your lists which is why it sometimes makes sense to create a list that starts out empty because it doesn't have to stay empty you can add more values down the line another tricky thing to understand about lists is that they are values and so you can have a list where one of the items in the list is itself another list or in fact even the very same list itself because when lists store values they don't really do so directly they store really an address pointing to that list just like variables are actually storing addresses of lists not the lists themselves directly so here if we have X and Y where X is this list with three elements and Y is this list with two elements then if I set to index zero of X the list which is Y this list is now going to be in place where the six was and then likewise if I set to X of one index one X itself that means that where high was string high this second position in the first list what's going to be there is the address of that list itself so in a sense the list is containing itself which sounds really weird but it is it's not commonly useful I mean it is sometimes useful but it's not extremely common but it is is it is sometimes useful anyway it is strange and so what happens now is if we get index zero of X well now that's this list here and so that returns that list and if we get zero from that then we're getting negative four so this whole expression here gets us negative four and then if we get the second element from the first list X well that's going to be as we said that's now this whole list itself and its index value index two is 78 so this whole expression gets us 78 now a very very common thing we want to do with lists is to loop through all the elements to iterate through all of the elements and so here we're creating a list assigning it to X it has three values and we want to create a list that no matter whatever the length of the list is it's just going to run through all the elements and so we can do so with a foreign clue where it has a counter I starts out with a value zero and which goes up to but not including the length of X so first time to loop the value with zero and the last time through the loop the value will be one less than length of X and so far let X has a like three the last time through X will have the value sorry I will have the value two so that means this loop is going to effectively print out zero and the first item of the list one and the second item of the list and then two and the last item on the list the third item on the list so this is the output we would get now it's so common to access the elements of a list in this form that we have another convenience on top of four and can foredeck we have what we call for each loop where you specify two variables I and V and then what goes here is just the list itself some expression either a variable or an operation that gets us a list and this loop will iterate for however many elements we have in the list and the first time through I will be the index zero then one and two and the three etc up to one less than length of the list and V will be the corresponding value at that index we don't have to choose the names I and V be clear but it's just a make sense in most cases I as an index and V as in value but you can call them whatever you want anyway so this code will do the same thing it's just a more compact way of writing the same thing we're printing out the index and the corresponding value each time through the loop so this is the output we get and just to be clear here's an example where we just directly are supplying a list to then iterate through with our our loop so this is legal you can just create a list right here and that's the list that we're iterating through with our forage loop so a list is a kind of value which stores other values and it stores them in order of position you have the first element of the list the second order in the list third the fourth etc a map is also a kind of value that stores other values but it does so in pairs what are called key value pairs and there's no sense of order amongst the key value pairs instead the keys have to be unique amongst the other keys doesn't matter what the values are it's just that you can't have any two keys that are the same because otherwise if two things are the same key and you specify hey give me the thing associated with this key it wouldn't know which one you're talking about so the keys have to be unique and usually there's strings they can also be numbers but they're usually strings and so here we have a map created with a map operator and you just write key value pairs with keys first and value so this is key high the value six key by with the value yo and there's nothing to indicate that it's just a matter of them being positioned in pairs but anyway so then if we do lend on this map well it has two key value pairs so we get a value two and then we can use the get operator and we specify a key and we get back the value associated with a key so in this case six for the value by we get back yo if we did get on a key that doesn't exist like say as if you would get back no try and access keys that don't exist you get back no okay and then you can use a set operator on maps as well and so here we have an empty map and if we then set to key high the value six this is effectively creating a new key value pair so the map was empty and a length of zero but now it'll have a length of one and then here we're setting to key by the value yo so we're adding the second new key value pair to the map and then if we set to high again key high again but now with the value eight we're effectively modifying what the value of that key is and that that key has a new associated value if we now get the value associated with high we get back eight not six it's still two key value pairs over so if you get lent x now it's still two and lastly with maps we can also use for each loops on maps very much like we can with lists the difference is that with a list the first variable here receives the numeric index of the position but there's no position for the elements of the map there's just a bunch of keys so instead what you get is the key and then it's associated value so if X here is our map and we're signing to K and V the keys and the values then we print them out one time to the loop the key will be by and the value will be yo and then another time through the loop the key will be high and the value will be six and be clear that maps have no sense of order amongst their key value pairs there's no sense of which is the first which is the second any of that so when you iterate through them there's no guarantee when you use a for each loop like this there's no guarantee in what order it's going to go through the map that's a implementation details we say it's depends on how exactly the thing is stored in memory and that's not really our concern in a high level language like pigeon so we should not expect any particular order when we iterate through the key value pairs maybe it'll come out with bio first event high six could be the other way around we should not have any expectation one way or the other one important thing about functions that we haven't mentioned yet is that you can treat them like values you can think of them as being values just like numbers of values or strings of values or lists or maps and this means that you can store them in variables you can store them in lists and maps you can pass them as arguments to other functions you can return them as values from some other function and so here for example we have some function Terry that has two parameters a and b and simply just returns multiplication of those two values but then in Maine if we have a variable in we got signed Terry to Ian and what that means is that if we call in like itself is a function and pass them as nine and three what we're really doing is we're calling the function Terry because Ian is currently referencing Terry so calling you like a function calls Terry and so what we get back here is it's multiplying a and b which is nine and three twenty seven so this returns twenty seven another thing we can do with functions that might seem strange is that a function can call itself this is called recursion the function can make a recursive call to itself and so here this function Jenny takes one parameter x and if x is greater than zero then it's going to print out high it then calls itself passing in one less than whatever x is and it prints out by and so in effect if from Maine we call Jenny with the argument three what you're going to see is high high high bye bye bye and the reason this happens is because in the first call to Jenny x will have the value three three will be greater than zero it's going to print out high and then here it's going to decrement three to two called Jenny with the value two and when one function calls another execution here in the original call is sitting and waiting for the second call to return right that's very important to understand and in that second call to Jenny is something very very important that second call has its own x when you call a function all the parameters and the local variables in that function exist only for that one call so if I have 10 different calls to Jenny each one has its own x that is totally separate from the others there's no relationship so when we call Jenny with the argument to x now having the value two in that call is totally separate from back in the original call where x had the value three so in that second call x will have the value two and two is greater than zero so it's going to print high it's going to make another call to Jenny where x will have the value one and one is also greater than zero so in that third call we're going to print high and it makes a fourth call to Jenny where x has the value zero zero is not greater than zero so in that last call the fourth call all of the stuff is skipped over that call returns and then back in the third call we're sitting here waiting for the fourth call to return and then we print by and then the third call returns in the second call we're sitting here waiting for the third call to return once it happens then we we move on and print by and the second call returns and then back in the first call where we're waiting for the second call to return that returns and then we move on and print by one more time the third time and the first call returns and then we're done so if you to graph it visually it sort of look like an accordion where the first call makes the second call makes a third call makes the fourth call, fourth call returns, third call returns, second call returns, first call returns. Now, this particular example of recursion is not at all really useful. There's no reason to structure the code this way. It's kind of strange. But there are cases where recursion does come in really handy. Here's a slightly more realistic example of recursion where we can define a function that computes a factorial. A factorial, if you don't recall, is like the factorial of seven is seven times six times five times four times three times two times one. It's that number that integer with all the integers less than it multiply together. And there's a special case where the factorial of zero is considered to be one. And so one way we can write a factorial function is recursively. We don't have to use recursion to solve this problem. But the factorial solution is quite elegant. And so we just first in factorial, we test whether n is zero. So if we want to find the factorial of zero, we'll get back one. Otherwise, if we're finding the factorial of some other number, then what we want to return is n multiplied by the factorial of one less than n. We're documenting n calling factorial recursively. And this makes sense because if you want to find the factorial of say seven, well, that's the same as seven times the factorial of six. And if I want to find the factorial of 29, that's the same as 29 times the factorial of 28. And so logically what's going to happen here is a quick example. So if I compute factorial of three n in the first call and we'll have the value three, this will not be true. So we come down here and we're going to multiply three times the factorial of two in the call. That's a second call to factorial where n is two. And this is again false. So we're going down here and we're multiplying two times factorial of one. This is still false. So come back down here and multiply one times factorial of zero and factorial of zero is one, one times one is one. So that that third call returns, excuse me, fourth call. Yeah, the fourth call returns one. The third call returns one. The second call returns two. And then back in the original call, it's three times two, which is six. If you're still confused, it's worth working it out on paper. And then I try a larger example, like say a factorial of six, you can work that out step by step. Do understand though, this is still not the best example of where recursion is actually useful in practice. Recursion and practice is typically most useful when you have data that is itself structured recursively, meaning like you have lists containing other lists and maps containing other maps. Then recursion does come in really useful and we won't demonstrate that here. But I did want to just put out the notion that functions can call themselves as strange as that may seem.