All right, no promises on how this turns out. I don't know if we're talking this thing here, so hopefully it works well. Okay, any questions before we get started? We're going to go over the practice midterm. Question about the homework, is that okay? What was that? Question about the homework. Question about the homework? Sure. So when we're doing pass by, I mean, there's already, there's, we've passed to a B, but there's also a B that's being initialized. So the scope, so for pass by name, the scope is defined based on where that function being invoked or not the body of the function. So the actual parameters, the scope is evaluated to say, okay, this B, this B right here, at function and vocation. And then when you pass by name, all references to that parameter reference that same variable. Yeah, it may come up today, we'll see. So the parameter, it's along those lines. Sure. In pass by name, the parameter is a local variable and it's passed by name to a function and everything refers to that local variable. Now, what if the function already has a variable, the same name as that local variable and the other function, but it originally referred to the global variable. Now it would just refer to that local variable, right? No, it doesn't change any, pass by name doesn't change any of the references, right? It just says everywhere that the formal parameter is seen in the function, right? Instead of using that formal parameter, you use the invocation parameter. Okay. Which that was decided to satisfy, right? So all of those other things, even though it happens to have the same name, that doesn't matter. It's still referencing to what it was originally referring to. Exactly, because you can look at that function and see, okay, all of these A's in this function reference that local variable and not a parameter. So pass by name, all of these pass by name, pass by value, pass by reference, these are only affecting the actual, the formal parameters in the function. Okay. All right. Any other questions before we get started? Can those? Sure. So would there be any, like, when I was doing it, it seemed like there was so much beauty. Well, I did it kind of like a spring processing, like a macro substitution. Okay. And I never really ended up using some shadowing. I never really had to go outside and get the theme or the color. Rather, I was just limited to the in the player. You should probably really look at how you're doing it. The scope is defined statically. The call by, it doesn't matter, any of the parameter passing does not change the scope at all. Right. That's the whole point of static scoping is you can look at the program and say every variable usage, I can map that to declaration. Right. For everything in the entire program. And call by, pass by name, it doesn't change this at all. So it's the only thing that it changes when you see a formal parameter usage. You know, okay, I go to the invocation of that parameter. You get the actual parameter and use that. But what that refers to, it still refers to whatever it refers to statically. I've never changed it. Probably for the... I think we're going to go over an example. Yeah, all right. It was with the print out, so that's why I was... One, two, eight, till after. And then you can see if you saw questions. Any other questions? Anything else from moment three? Hello. Well, I think we're going to have some problem terms. Maybe not that bad. I think last time this happened, I even said I should get a new battery. Maybe you happen to have a nine volt battery in there? Backpack or on their person? No? So unprepared. Not an electrical engineer. Not an electrical engineer? No, that's true. Hello, battery, low battery. Yeah, that one doesn't work. I think it's going to be an exercise. Hello. Hello. Oh, good. That's a full battery. Okay. Yay. Yay, exactly. Yay indeed. Okay, so to answer that question that was in the front, the question was about problem three on the homework, and I said let's get to that at the end after we go through an example on the midterm. Any other questions? Yeah. So let's say you have some actual parameter, let's say, and you are updating that in the function to three. And then, you are using that actual parameter as an index of some value. As a what? For something? So there is an actual parameter which is having value two, let's see. And you are updating that actual parameter to some other value, let's say three. Sure. And that value you are using as an index for an array. Okay. So it will be the update value. So it's in the homework function. So it will be the updated value or it will be the prove or treat. Well, in pass by name, right, every time you see that parameter, that expression is evaluated every time you see that parameter. So something in that expression changes in between usage of that formal parameter. Then whatever that expression is going to change. But that's not the case with the value. Why not? Oh, it's not the case with what? Right, those are, maybe the expressions are evaluated before the function is called and the result is passed to the function. Okay. Let's get started. I think a lot of these questions are going to answer here. All right. So we have good old problem one. Ooh. Every favorite, typically familiar type of inference. Okay. First thing, right, read everything carefully. Always important on every exam. I really shouldn't have to put this here. You should be reading. Another good tip that maybe you're not aware of when you're taking a test is to read all the questions first before you start answering anything. And if you know the answer right away to something, you can write it. But at least read through them all and then you can go back. Not only when you're working on one problem, your subconscious brain is solving, like, the last problem. I guess that's a good idea. I guess. Okay, read everything carefully. Some statements can be tricky. I hope that's self-evident, right? It's a problem for ourselves. Okay. So here we have a defining of function f that has how many parameters? Four. Four. A, B, C, and D. And the body of this function is 1.0 plus the expression if A, then B, C, D. Otherwise, D, C, A. Okay, so since I'm super nice, I do this abstract syntax tree for you. So you can use this to solve it. Yeah, sure. Cool. Okay, so, okay. Here we have the abstract syntax tree for f. Now what we want to know is, well, first thing, right? Before we do anything, we should go look and see what the question is actually asking us to do, right? That's why it'd be something that it's not asking us to do. So it says, okay, we know the type of A, the type of B, the type of C, the type of D, and the type of f returns, and the type of f. So are these all questions that you are well equipped to answer? Yes. Yes. Awesome. Okay. So now we want to do this to understand. So we need to know some things. This is the way to do this. Sorry, I forgot to tell you this a little bit. All right. So we can keep track of some of the types that we care about, right? We want the type of A, the type of B, the type of C, the type of D, and then we need, okay, so we know that f is a function. So we know something about the type of f, right? What do we know about f from this definition here? T-A-T. How many parameters is that? Cool. We've got four parameters and returned something, right? Yeah. So we know just from this definition, right? We know f, so the type of f is a function which takes in a type of A, a type of B, a type of C, a type of D, and returns some type of T-1 that we're defining right here. Right? So which on this whole thing is T-1? Fun. No. Plus. So if fun returned one, that would mean whatever the function definition returns, right? Which doesn't really make sense. We kind of have to talk about that. Okay, so we know that whatever this node is here, which we can see is this plus operator, that has to return type T-1. And we have that constraint just by looking at this top level. I think here. Okay. Just a quick question. Yes. Are you going to be posting this? Yes. Sit here, fall asleep. Okay. Let's talk about this. I don't know. I don't know. Okay. It's fine. Okay. So now, so one thing we can do, right, we can number all of these nodes, give them each a type. I'm going to kind of skip that step because the types kind of get very long here. So anytime I need a new type, I will create one and add one here. But here's all we know about the types, right? We don't really know anything. Let me have this constraint on the type of that. So I get here to this plus. Okay. Plus, arithmetic operator. What does that tell me? What constraint does it tell me about the types of that node and its children? They all have to be the same. Yeah, exactly. So the left child and the right child, both have to be the same type and whatever they return has to be the same type. So I know this has to be a T1 and this one also has to be a T1. Do I know what T1 is yet? No. Yes. No, I don't know yet because I haven't looked at any other nodes. I just know that all three of these nodes are T1 and I know that F returns to T1. Right? But now I look at this child and I say, okay, what's the type of this child? A double flow, what's called a real? Right? Because that's kind of what you're using in the homework. That's normal. So at one point there was a real number. So what does that mean about type T1? It's real, right? So this is the constraint. The constraint right here is that T1 is a type real. Great. So now we can say, okay, T1, you are real. Perfect. Okay. Now I go to the right child of this plus node. So now this T1, I know what it is, right? I know it's a real. It's got to be a real. Okay. Now this is an if node. So what do I know about the constraints? So let's... So what do I know about the constraints of an if node? Yeah. The left-most child is S3, sort of, T1. So this has to be a Boolean. And then what else? Somebody else? What else? Yeah. The calls have to be T1. The calls have to be T1. Why? Because you want to return something that's being added to a T1, so they have to be the same place. Right. So if there's... It doesn't matter which branch I fall down or which branch I go down. Either one I choose in order for this to type type has to be the same type, right?  Well then that could be that branch. I know both of these branches have to return to T1. Yeah. That only applies though because the 1.0 plus aren't right. It wouldn't be the case if that 1.0 plus was there. Did I put reals here? What did I do here that depended on this being a 1.0? Which one? Huh? Wait. You said... So you said would this be the case if this wasn't a 1.0 here? But did I put... What did I put here? No. I mean you have that match of the type of whatever you're adding, right? Because I'm saying the two branch can return to different things if you didn't have that constraint originally. Correct. I just wanted to... But no, the problem, the constraint is that whatever the int state then returns, right? Both of the true branch and the false branch must return that same thing. We don't know what it is but they have to be the same. That's the only constraint we have. Otherwise it doesn't make... you can't type that right because the text is a variable depending on what branch you go to. So yeah, it has nothing to do with the fact that this is real. You just took another step of explaining why it starts in a specific program and the types will probably be incorrect. Okay. So now I go to this left branch. Now what does this tell me? Type A is a real or is it Boolean? It's dense. Okay. Which we know because A is on the different. We know this node has to be a Boolean and we know the type here is type of A. We know these must be the same. So I can say the type of A is a Boolean. Do I know anything else? Okay. Cool. All right. Let's go to another call. All right. So now we see a call node. What does this tell us about the call node and its children? What constraints? Left side of the call node should be a function of some type and the right side should be the parameter. So the left side should be a function and the right side should be a parameter. Yeah. So about this function how many parameters does it take? One. What is the type of that parameter? D. It's a type of D we can go a little bit instead of getting it as a type. Right? Exactly. And what does it return? T1. T1. Exactly. So we have all that information here. But just from looking at this call node that gives us this good train here. Okay. Any questions? I don't know. I don't know. I don't know. I give people a chance to ask questions. All right. So let me go to this next node. So this is what kind of operator is this? array, array access, right? So this is the array access operator. So what does this tell us about it's type and it's children's type? Yeah? C is having a type int. The right child is an int. Yeah? What about the left child? Left child is an array of int. A array of what? Int equals, sorry, tt, tt implies tt. Array of tt implies tt. Yeah, so if we, so yeah, so b, this means for this type check, right, whatever this left side is, must be an array, right, which makes sense, of, but what is an array of? Well, it's whatever its parent is, right? So it's an array of td, a function that takes in type td and returns a type t1. All right, so then I look here. And what do I know about C? It's an int. And then I look here, what I know about b. Right of functions, and each of those functions has the type, takes in a type d and returns a type t1. T1 is a real, oh. OK, so we're done here, have we seen any type errors, any contradictory, no, right. So now we got on this next branch. So now we see this is a call. So what do we know about a call? What are the constraints? What about ints and its children? What's got is what? The right child. What, is that not? Take it back, I don't know any children. So we see this call function, what do we know about it and its children, right? Yeah, 30 left child is a function and the right child is a parameter. Perfect, so then what do we know, can we write down the type of this function? Right, perfect, and that's everything that we have here from this, from this branch, right. We have ta, which is a Boolean, so this is a function that takes in a Boolean and returns an a real. Is that a function that you can write? Yeah, absolutely, another example. OK, now we're on our last node. So here we have a ray access operator. Then what do we know? What was it? Season int. Season ints, OK, this node must be an int, what do we know about the left node? The ray of its parent. The ray of its parent, exactly. So it's an array of ta goes to t1. And so I have c, here this says c is an int. Was that type text? Yeah. Yes, so we already have c as an int, so that's good. If there was any other basic type, we'd say no, that's an error. Then we say, OK, type of d is an array of Booleans, a function that takes in a Boolean and returns a real. So is that type text? And returns a t1 to the real? How do we fill in the blanks? Oh, question. Yeah, so the reason you don't get a type error because you use d as a parameter without a parameter itself, and then d as an array with a parameter because d is not a function itself, just an array of functions. Well, even if d was a function, if we pass a function, it would do another function. Right, but what you need to include the parameter is if you have a function that takes a parameter and when it doesn't, you might choose a parameter. Yeah, wait, but no, this is being passed in as a value to this function. Right, but if it was a function that took a parameter and it was being passed in, it doesn't matter because it's just being passed in a function just like passing an array in it, right? As long as a function is expecting an array or a function of whatever type that you're passing in. So yes, if it was a function that required a first parameter, a function with no parameters and you give it a function with one parameter, that's a type error. But you would infer that based on the usage here. So here we know that we're passing in d. So it's really the fact that we don't have a type error because we got no contradictory constraints. So the last thing from what we're used to with c is that this is not a call, right? You're not calling a function, there's a function that's going to, yeah, he's going to be subsequently used inside of the other function. Exactly, and how would we know if d was a call? It would have parameters, it would also be in this tree, right, this tree would be a call and we'd have d on the left and nothing on the right. That would be a call to a function with no parameter. Yeah. So if we're considering structural equivalents and we're comparing whether a race are structurally equivalent, do we need to consider the dimensions and the length of each dimension? If they have dimensions of length, then yes. Otherwise just by our assumption of truth, we just pick it up and prove it. Right on structural equivalents, we're just saying. Exactly, yeah. All right, any questions here? All right, so then what's the type of A? A bullion, the type of B? Array of type T-B, let's take D. It's an array of bullions that are termed reels. Just a term of reels. Oh, right, so just simple substitution. So we say that what we know from our analysis that for this type check, B has to be an array of functions, each of those functions takes in something of type D and returns a real. And so we just simply substitute. We say, okay, what's the type of D? Oh, D is an array of functions that take in bullions and return reels. Great, so that means B is an array of functions. Each of those functions takes in an array of functions and all of that returns a real. On the exam, if we left it as T-D, would it be marked off? If you left it as T-D, would it be marked off? Just a little less to it, I don't know. If we know, if we have a right answer for a type of D and we just left it as T-D, say it applies to that way. Uh, I would, I don't know, it's tricky. I think I would probably write a word in here of simplify as much as possible to get rid of those types. Okay, because that also helps you to make sure that you know what you're doing. You get a partial credit at least. Yes. Yeah, I would pick up a bunch of points, but it's not, it's not really what we're looking for. All right, perfect. Okay, so the type of C, all right, I moved up a little bit. I have two cameras to work with. It's actually kind of a problem. Okay, okay, so the type of C, the type of C is an int. So the type of C is an int. Type of D, so there you know it's an array of functions that take in a boolean return of real. Okay, what's the type that F returns? Real, yeah. And what's the type of F? So it's a bool, it takes in a boolean. So you guys should take a test of 150 people on it. That's an int. And then D is an array and this whole thing returns a real. So you can call function F by providing a boolean. And if this boolean is true, then it's gonna use, it's gonna pass this, it's gonna pass whatever parameter D is into the, yeah whatever, you're gonna have to create this. All types, types, yeah. On the exam, the students here probably didn't want us to show what if we do get it wrong, would that be sufficient enough, like you didn't ask for it, or if you actually want us to put it in the table? The table could be more clear. I mean this is probably your best bet is showing here where all the, like where you're putting some strengths. Be even more clear, you label each of these with a node and then you kind of like mark your constraints as you go through, yeah. Why is there an arrow real for that? Why is there one here? Yeah. What's the type of F? What does that return? Oh, okay. Right? Yeah. Cool. Probably got another question too. Okay. Problem two, so we have a list of types and we have questions about those types and we have a list of variables and we have questions about those variables. So this says for each of the following types, list the types that are equivalent, assuming structural equivalent. So do y'all remember how to do structural equivalent? Perfect. Awesome. Okay. So we can do, it's the easiest way to do this. We can do our table here of the types, right? Zero, one, two, three, four, five, six, seven, eight, nine. So zero, one, sounds really good. What if this comes before you do this? So we know that all the middles, bro, right, are gonna be the same. So I'm gonna do the check mark for equivalent and then x for non-equivalent, right? So we start off by assuming that everything is structurally equivalent, right? Questions? Just writing. All right, so zero and one, are type zero and type one structurally equivalent? We have a pointer and an integer, doesn't matter. A pointer can only be structurally equivalent to a pointer that also is pointed to the same thing, right, so you have an integer, the basic type of a pointer to a basic type. I'm not saying that. Do I need an extra line for what? So I know zero and one do not, are not structurally equivalent, right? Yep. So I've got an x, so I've approved that. Zero and two, a pointer to a t zero, so same question, right? Point or two and int and int can't be the same. Actually if we look, we see pointer, pointer, pointer, struct, struct, struct, struct, struct, struct. Can an int ever be structurally equivalent to a structure? No, it doesn't matter. No, it doesn't matter. So we can know by looking at this that these are all not structurally equivalent. That make sense? Right? This can only be half the graph. Yes, we're only gonna be half the graph. So we're just gonna go, we're gonna start here with one and two. But yeah, this is a quick check, right? So we know that these three can only possibly be structurally equivalent, right? Because they're all three pointers. We know that t four, t nine could be structurally equivalent to their structures, but they can't be structurally equivalent to each other and have pointers and structures being structurally equivalent. Okay, one and two? Why yes? So they're both pointers, and then what do you do? Compare with them pointing to, right? You say our integers and t zero structurally equivalent. So are they? Yeah, exactly. So we say t one and t two are structurally equivalent, or they remain structurally equivalent. T one, t three? So t one is a pointer to an integer. T three is a pointer to t one. So what's the full type of t three? Point or two, a pointer to an integer, right? So is that ever going to be equivalent to a pointer to an integer? Nope. And then we know t four through t nine. There's no way these can ever be structurally equivalent. Okay, type two and type three? The pointer to t zero and pointer to t one? Yes? No. No, why no? So you're using this last one. The entries are this last one, yep. So those definitely aren't structurally equivalent. And t two and t four, all of these are not structurally equivalent. So we look at t three and t four. We say are these structurally equivalent? No, why not? No, definitely not. So t three is not equivalent to any of these. All right, so now we go t four. We say, okay, it's t four and t five are they structurally equivalent? Yes. Yes, why? How many fields do these structures have? Two. Two? So they're both two, right? So that's good, that's the first sign. And then the first field is one type. It's int that matches and the second types. Int int, does it matter if the names are different? No. No. So they go great, four and five are the same. All right, four and six? No. Why no? Are they the same number? Yes. Yes? So this first one is, let's see, where are we? Four and six. So this first one is, okay, so for them to be the same, now we mean that int has to be structurally equivalent to t seven, is that the case? No. No, so we've just proved that. The other way we could look at it is we look at the second field, right? We can say it isn't int the same as an array of t one. No, can't ever be true, so not structurally equivalent. Four and seven? No, by the same reasoning with this array as the second parameter. Four and eight? No, from the same reasoning, right? So the second parameter is a function and the second parameter here is an integer, right? So can a function and an integer ever be structurally equivalent? No. And the same with t four and t nine? Right. Questions on that so far? Yeah, just a quick question. Yes? Let's say for t five, t one, eight is still structurally. So the names are the same, but the orders? Does that mean the correct answer? In our structural equivalent, it's the only thing that matters is the order. The names don't matter at all. So in that case, it wouldn't be structurally equivalent? Correct. They would be not structurally equivalent. Okay, so now we look at t five, and we say is t five structurally equivalent to c t six? No, definitely not. The second parameter here is an int. The second parameter here is an int. So we know it's definitely not. What else could we use to say it's not? It's t four, t four. Yeah, it's structurally equivalent to t four. So if t four is not structurally equivalent to t six, t nine, then t five definitely can't be structurally equivalent. But if you don't want to rely on that, so maybe we made a mistake with t four, right? We could just look briefly so we can say, okay, t five and t seven. Well, this is an array here. Array can't be the same as an integer, so that's definitely not structurally equivalent. Let me say, okay, t four and t eight. Well, this is a function here, and this is an integer on the second parameter, so that's definitely not structurally equivalent. t five and t nine, same thing, function, integer, not structurally equivalent. All right. Okay, t six. So now t six and t seven. So are these structurally equivalent? Seven, seven, eight, seven, eight, seven, eight, seven. Since t is a stroke, can you compare what's the size of that stroke? Or do you compare what's the size of that stroke? So how do you compare the types of two structures? I look inside the structure to be exact. So it's one of these kinds of recursive things, right? So you want to say, okay, if these structures to be identical, it means that all their fields in order have to be structurally equivalent. So, okay, for our first go-through here, so we have t six and t seven. So we say, is t seven structurally equivalent to t eight? Yes, right? We can look that up at our table. You can see seven, eight, we haven't drawn an explicit check mark here, because we haven't looked at it yet, but as far as we know, we're assuming that they're the same. We say, okay, that's fine. And then we say, okay, so now t six and t seven, array of t one, array of t two. Is an array of t one the same thing as an array of t two? Yes, yes. How do we know that? Because they're both structurally equivalent in our table, we have t one and t two, right? So these are both, both integers are both structurally equivalent, and we have arrays. So the arrays are equivalent if what they contain is equivalent. So for right now, we say yes, this is structurally equivalent. Okay, six and eight? No, definitely not, arrays and positives here. Six and nine? Oh, same reason. Okay, seven and eight? So look at this, t seven, t eight, are you structurally equivalent? Yes, yes. Yes, does this feel great? Now we go on to the next field. Is an array of t two the same as a function that takes in type t six, t four, in terms of n. Nope, so that means t seven and t eight are not structurally equivalent. T seven and t nine? No, definitely not, right? We have an array and a function. All right, we have t eight and t nine? Yes. Are t seven and t six structurally equivalent? Well, we have all we have in our table. So what does the table say? Yes. Yes. Okay, great. Now the functions. Do the functions have the same number of parameters? Do they have the same return type? Yes. Do they have the same first type? Are these two first types structurally equivalent? T four, t six, no, so this whole thing is not structurally equivalent, eight, nine. And then we can go through this whole thing, but we kind of know the only thing that really changed the effects of anything is t six and t seven, which we've shown that because t seven and t eight are no longer structurally equivalent, and that means t six and t seven are not structurally equivalent. All right, now I can answer this question very easily. Like I said, okay, let's reach to the following types. What's the types that are equivalent? So type t one, what types are structurally equivalent? Type t one, t one, t two, t three, t three, just t three, t five, just t one. Just, wait, t four and t five, right? T seven, just t seven, and t nine, just t nine. Any questions? We'll go with that. When we get marked up, we'll write down the same ones. Type t one, just write it down, t one, t three. So in this case, if you wrote nothing here, should you get any points? No. Yes, yes. If you wrote none, I would probably take that as, well, I think you wrote none. If you did write anything, you wrote something there. Actually, if you wrote none there, I would probably accept that, but you should write all the types that are equivalent, right, because that's what it's asking you. Because otherwise, I'd have to grade it and some of you would have to have it blank. I'd have to give them points here, right? Okay, our structure is equivalent, right? t three and t three are structurally equivalent of all the types that are. Okay, then we turn our attention to the variables. We have x, that's an int, a y that's an int, a z that's a t zero, a p and q that are a function that takes in type t five, returns an int, and r that's a function that takes in type t five, returns an int, and s that's a t five and a t that's a t six. So it says for each of the following assignment statements, indicate if the statement is valid under structural equivalence, name of equivalence, or internal name of equivalence, which should be, let me make sure I'm good on that. Okay, quick. Okay, so write a one if it's valid under name of equivalence, two if it's valid under structural equivalence, three if it's valid under internal name of equivalence, four otherwise, what's a really important thing that you might miss if you skim this? Well, four, and write all that apply, right? That would be something that would be bad if you missed. Okay, x is equal to y. Can x be equal to y under name of equivalence? No? Yeah. So why yes, why no? There's a suit to be split. No, we also defend there. Five? They share the same type but not the same name. They share the same type but not the same name. Yeah, what's the name of the type? It is. You know what you and the name are very, very important. Right, so they share the same type of name. The name is int. So name equivalence, structural equivalence, are they structural equivalence? Yes. Yeah, I hope so. And do they have internal name equivalence? Yeah. Right. So why, if I had, let's say, who, are these name equivalence? Why are they different? What was that? It's not the type. Right, this is a, I've created a new type. Right, it doesn't have a name, it's an array of integers. Right, whereas here I'm using a type that already exists which is a type int, so int exists. So these are type instructors, right? I as a programmer am creating new types. And here I have not given them names, so these are anonymous types. Are they internal name equivalence? Are they? Let me have a minter and do this. Are they internal name equivalence? I was going to ask about that. Oh, there you are. I was going to ask about the person. Yeah, why are those internal name equivalence? Because they are, they have the, they have, if they're name equivalent, they have to be internal name. Like they have to have the same, they have the same name, the name is integer, that means internally they have to be represented by the same name. And assign two different names to each of them so when you compare them. Right, it's two different decorations of anonymous functions. So there's two different anonymous functions. Two different anonymous types here because they happen on different lines. So, y and z, are they name equivalent? No, right? Because they have different names, t, zero, and int. Those are different names. So, not name equivalent. Are they structurally equivalent? Yes. Yep. Are they, do they have internal name equivalence? No. No, because they're t, zero is defined here and int is defined by v, five. Okay. v is equal to q? Yes? So you said if it's name equivalent then it has to be internal. But if it's internal name equivalent, does that also have to be name equivalent? If it's in, no, no, because they don't have an explicit name. Right, so yeah, internal name is before the last. Okay, let's look at c, q. So, are they name equivalent? What's their name? What's the name of the function? It doesn't have a name, so they're not, so it's not name equivalent. Are they structurally equivalent? Yeah? Are they internal name equivalent? Yes. Yes. All right, so that's your question. So here's, that's right, not name equivalent but the internal name equivalent. Okay, q and r. Are q and r, so q is here, r is here. Are they name equivalent? No. No, are they structurally equivalent? Yes. Are they internal name equivalent? No. No, right, because they're defined on separate lines. They are two different anonymous functions that have, or anonymous types that happen to be structurally equivalent. Okay, c is equal to p, s. Or call p as a function to pass in an s. So is this a valid, does this function call type A? Yes. So p as a function that takes in a t5 returns an in. S is a t5, right? So then what is p of s return? An int, and so is an int and z, is it name equivalent? No. No? Is it structurally equivalent? Yes. Is it internal name equivalent? Okay. All right, x is equal to pt. What's the type of p? t5 returns an int. What's the type of t is t6? t6 and t5 are equivalent, right? t6 and t5 are what? R, equivalent. Are they? R. T5 and t6, no, are not equivalent. So then it doesn't work. So then it doesn't work, right? Exactly, you can't call that. That's a type error here. And what we do is? Call R. Call R, otherwise. Huh? You can't specify what it is. Keep going, yeah, the question. Well, it depends on what it is. 2 equals R, why exactly is it not internal? It's probably correct. 2 equals R. 2 equals R? Yeah. Because they're not the same definition of an anonymous type. So here I'm defining two variables p and q that have the same anonymous type. So they have the same internal name. But here on the next line I'm defining new variable R that is a new anonymous type. Just because those are structurally equivalent types doesn't mean that they're internal names from one. So anytime you make a declaration of an anonymous type, it's just a particular declaration. Exactly. Yep. Is that good enough? Okay. Okay, so problem three, consider the following C code. A function foo, a function bar, a function main. Bar has a local variable called baths. That, okay, it is. It sets baths to the result of foo zero. It sets baths to the result of bar of baths. So it passes baths into bar and returns baths. The important thing to do is to look at what the question is asking us to do. Draw the program stack at the first execution of location one, specified as a comment. So this is what we care about here. All right, location one. Label on the stack all function frames and each side each function frame labeled a parameter to the function. The values of those parameters, the function's local variables and the values of the local variables. You don't need to follow precisely that the common conventions assume static scoping and pass by value semantics, right? Very important. Okay, so let's look at this. Okay, all we really have to do is simulate the execution here. So we know, so we kind of want to look ahead a little bit, right? So we know we are hitting location one when the parameter to foo is 50, right? So we know when this function, the code executes, it's gonna start executing on main. So then we can draw main's function frame, right? And main, does main have these parameters? Yes. No. No. Does that have any local variables? Yes. Does baz have a value? No. Nope, not before we execute it. Okay. So now we're gonna call the function foo. What are we passing as the argument for foo? Zero. Zero. Is zero 50? No, so we know we're not gonna hit location one. So we want to simulate the execution, but we don't really care about drawing it through. No, because we're gonna have to get rid of it, right? We can draw it and then we'll move it and maybe we should do that because I don't know. Okay. Here we have our foo where we passed in, it has a parameter x, what's the value of x? Zero. It has a local parameter, a local variable a. So as it executes, it sets a to be 10. It sets a to be 10 and then it returns x plus a. So it returns 10. So now this function returns, we go back here. This goes away. And now we set baz to be what? 10. All right. Then we call bar passing in baz. So now we're gonna have, so I don't wanna go up there, call it, that's fine, can we go next to it and see this? Yeah. Okay. So now we're gonna call bar. What's bar's parameters? What's y? What's the value of y? 10. How many local variables does y have? Two. A and D. Okay, so bar's gonna execute and it's gonna call, first thing it's gonna call is foo y. So it's gonna call, I'm gonna run over here. All right, it's gonna call foo y. So now it's a function call, so it's gonna allocate more space. So it's gonna call foo. And foo has a parameter x. What's the value of that parameter? 10. And it has a local variable a that after this executes is gonna have a value of 10. And it's gonna return 10 plus 10, which is 20. So it returns where does it point? D. Then we're gonna call foo 50. All right, create a new frame for foo. So foo has one parameter x. What's the value of that parameter? 50. Foo has one local variable a. A has the value of 10.  And then we're done. So if I'm gonna draw this in a normal way without all that stuff. Function frame for main, a function frame for bar. And a function frame for foo. If that was a local variable, it would just not be essentially function at all. Correct, okay. Yeah, any local variables, right, will be wherever right now on the stack. So we're gonna draw that. Yeah. So this is what you want for now.  This is sort of a way of pushing the local variable like this. The last question about the local variable. Oh, if that was a local variable, you wouldn't write it on the stack. It's not on the stack, it's a local variable. Yeah. So would it be overkill to say that the caller puts the return address, you know, these kinds of things, no? It would be overkill, you can do it, but it's not necessary. It's not why I wanted to put this on here, right, it's on this way. And so that's all you want for the homework template. Okay. Hey, hey, hey, you got your boss to watch this. He needs to help you. Yeah. So what happens if I have to print that statement anywhere in here? Why not? You're not storing values in here now. Will it close the function of return? Exactly, calls the function returns just like this first call to function foob, right? He calls it, creates a stack, brings it then returns. So yeah, we don't care about that, right? So this location, right, this is the whole stack that is currently active as that location. Hey, hey, hey, hey, hey, hey, hey, the question. I'm not, yeah. Yes, that's why X is here as 15. Exactly. So that's why I have here as, so you got to make sure you're putting the parameters here and because it's passed by value, those values are actually on the set. And other important things, right, is that A does not have a value again. So if you put a value for A into something far, that would be wrong. So the order, does the order of the variables matter? No. And then the second question is this. So wait, okay, let's rephrase that. So no, the order of the variables doesn't matter. But you should be consistent, right? If you have the same function frame multiple times and your variables are all in different orders, that's where you really don't understand what's going on here. Yeah, so the second question would be, is this what we need to know for the exam versus the C-devil that was in the slides? Well, you may need, for a question like this, this is what you have to do to draw a stack, but you may have to ask questions about the C-devil calling convention. But it wouldn't be anything involving like assembly. You would not have to read or understand the assembly or if you did, I'd give you what it is. But you should know what it is. You should know who does what with the calling convention. Those are important things. Are we always going to assume static-stoping on the test? Or will you grow in dynamic? I could do anything. You know what I'm giving you? You're just giving me more ideas. No, stop it. You don't want a good question, do you? It doesn't matter. It's okay, because I love that. It doesn't matter that it's a basic right? Yes. Why? Because, like, if you have an unidentified pointer, there's still something there in the memory, right? So you can just use the same thing as a struct. A struct is just the thing with lots of memory. Is the space not in the right? Exactly. That's why you put nothing there, because you don't know how to play it. But if you put, like, zero there, that's pretty wrong of me, because it's not zero. Some kind of product. Zero. I'm not using the same product. You're assuming it's a bunch, right? Okay. Let's finish up problem four. So that way we can get all this done. It's all recorded. All right. So the last problem. Consider the following code in C syntax. Use static-stoping. So here we have a global integer a. You have a function f that takes in the parameters x and y. Oh, those aren't in types. Sorry. I have another CD. This is actually a valid CD, because I did run this, but... So I think it assumes an integer code that's supposed to type, but it's still there. It really bothers me. Okay. So we have a function f that takes in two parameters, both of them type int. f sets a to be three. It says x is equal to x plus one. Y is equal to x minus one. Does it return anything? No. No. It's got a void type. All right. Main sets a local variable b to be zero. It declares a local array of integers called c that has four integers there. So c zero sets b1, c1, b2, c2, b3, c3, b0. Then it calls f of passing in b. And then c bracket, c bracket b. So what are the bracket operators? Pre-access, yes. Just one over that. Half hour. Okay. Calls that function, then prints out a, b, c0, c1, c2, c3, returns. Okay. Then we want to see what is this question asking us to do. The parameters are passed by value, what's the output? If the parameters are passed by reference, what's the output? If the parameters are passed by name, what's the output? So test taking tip. What do we know about the output of this program in these three different ways? What? Possibly different. Possibly different. That's one thing. One other thing. Close it? Yeah, the number that it's going to print out is always going to be the same. One, two, three, four, five, six. So if you put not six for any of these, it's a very easy way to lose points. At least put the number there. You're not sure, right? Might as well guess. Okay. I mean, do you think it's right? Is it more likely to be right than any other numbers in your actual project here? All right. So let's look at this function. All right. Pass by value. So this should be incredibly easy, right? Because this is how you post, right? This is what you've been taught and built on. So you should be able to easily do this. Okay. So pass by value. So f gets called. Does that return anything? What does f change? Since a to be three, if we pass by value, you're going to use x equals or y equals kk, right? No. No. So then, what do we have going here? So it's a. Three. What's b? Zero. Zero. C zero. One. One. C one. C two. C three. Zero. Oh. You've got a lot of points. All right. If parameters are passed by reference, the output of this program is the following. So now, does it matter what happens in this function? Yeah. Yeah. Okay. You can't really see it. Oh. I mean, super zoom in on this thing. Okay. So. Does it matter what happens in f at pass by reference? Yes. Yes. Why? Because when we assign in here, the location that is passed in is a parameter, right? So that will actually change in effect whatever is passed outside. Okay. So let's think about this. So we have b zero. So b zero, we're going to pass by reference. So b is going to get passed in for x by reference. So anytime x gets assigned to you, it's going to change the value of e. Right? Yeah. At the same time, before function of a patient, we have cb. What's cb? C zero, which is one. And what's c1? Two. Two. Okay. But we're talking about L values here, right? So we're passing in the L value of b and the L value of c1. Right? Because the semantics of pass by reference is we evaluate this and then we use that L value to pass it. Right? So is there an L value for c1? Yes. Yeah. You can draw the boxes. Right? That location right there. The location that currently has two in it. And then we're going to execute this function with pass by reference. So we said a equals three. Is that changing anything? No. It changes the global age of three, but not anything from the previous execution. Right? Okay. x is equal to x plus one. So what's the x on the right here? It's b. So we're going to make the value, the value that's associated there with x, which is b. So zero plus one is one. And then we set that into the L value associated with x. We're going to do what? We're going to set b to be one, right? Now here, the next line says x minus one. So what's x? One. One minus one is? Okay. See, it's not hard math. Okay, zero. And we're setting it to be y. What's the L value here? C one. So we said C one equal to zero, right? So then this returns when we print out. So what do we print out for a? Three. What do we print out for b? What do we print out for C zero? C zero is one. C one. Zero. C two. C three. Alright, pretty easy, right? Pass by name. Is it harder? Okay. Let's get the problem up there. Okay. So here we're going to do pass by name. So one way to think about that is that this function call is going to be changed, right? So this function call is going to be replaced by a is equal to three. b is equal to b plus one. C bracket c bracket b is equal to b minus one. And let me print all of that. So I just replaced all of the x's here with all the y's here. So if I had an int, if I had an int c here, and I said c is equal to ten, do you think I'm good here? No. Why? It's a local variable. So this instance of c, where does that define, where does that math to? Where's the definition of this use of the function c? Right above it, right? The local c, right? You know that statically. So we know the static rule, we know it's this static c. This c here, where is this, what is this referring to? The array. Exactly. So this is all done statically. So if I have two packs by name, what I'm doing is I replace all instances of the parameter x. Which is the parameter x? Here? Here? And here, right? Three places. Those are the x's I replace, and I replace them with this expression, but everything in that expression refers to where it refers to in its use. So this c does not refer to this integer c in here, right? It refers to this c here, because we know that because it's done statically. Okay, so now it's executed. So we have to hear b is 10, so we set a to be 3, right? That's what we've been doing. So b, so b is currently 0, 0 plus 1 is equal to b, so now we change b to be 1. I'm going to cross this out there. Okay, now I take b minus 1 on the right-hand side, so what's this? 0 again. Then I take c of b, what's b right now? 1. b is 1. We just updated b right here, right? So b is equal to b plus 1, so b is 1. So what's c of 1? 2. And what's c of 2? 3. So it was 3, now we're setting it to be 0. And then this function returns, and we try to talk about it now. So what's a? 3. What's b? What's c of 0? c of 1? C3? C3? Okay. All right, we've got five minutes. Questions on the different stuff? Hey, maybe we can, everything up till today, you've got things that we learned, right? So you need scope, in order to even answer this problem, you need scope and rules, all that kind of stuff. Commandant. Hey, hey, I can't hear. So if I had a function, food like this, that has local variables b and c, b is 100, it doesn't pass my name into food, from c, it returns b and c. So is this what your question is? What happens here? So we're, so this is the formal parameter x, right? Where are all the instances of this formal parameter x? Here, right? One is this. All the rest of these variables here are not the sixes, they're poorly gone b's. So if I was to search all of these b's, these all refer to that same, scatically, these all refer to this declaration of b, the local b, right? So when I do pass by name, in this b, where does this b refer to? This one, right? The one in main, exactly, the main's local variable b. Only the x is connected. Exactly, the only thing that changes when we do pass by name is we change, so we replace the name of the usage, but we don't change any of the scoping. The only thing that changes is that x. So we replace every instance of that x with this expression, where this expression, scope, has already been decided. So we know that this b corresponds to this local b. So we can say if b is equal to zero, if b is equal to b plus one, b is equal to b plus b, we'll call it b half, because this b refers to this. So this will be zero, this will be zero plus one is one, it'll be one plus a hundred is a hundred one, it'll return a hundred one, it'll bring up a hundred comma one. So let's say that same line where we have b hash, we have equal to b plus, yeah, obviously we have that. So that would also be a b half. Exactly, so all of these all refer to that b. Okay, let's go. Cool, alright. Last question. So could you get away with this, too, and the local b could read in to b half, basically. Yeah, it's something to say to be like, doing b half, right? Yeah.


I'm Janine, I am a project manager at Big Boom Design here in Asheville. I've been at Big Boom for about two years and it's my first project management gig. I'm really excited to be here with you guys today as a new-ish PM because I know we all struggle with the same things at pretty much every level. Project-based work is hard. Getting projects to be good and not bad is tough enough that my job exists. We are a small team of eight, all local, so most of us wear different hats. Some of us are remote or have different office schedules. So it's a fairly complex management predicament but easier in a lot of ways. We all have some sympathy for each other. I think a broader grasp of what everyone does and a better sense of what we each don't know, I think, because we've all had our hands on all these different problems at different times. And it's lucky for me because folks in other companies admit they don't see the value in what I do. My favorite project management podcast, the PM happy hour, recently recapped a survey conducted at the PMO symposium, which is this big conference for big companies talking like employees in the thousands that have like a dedicated project management department. Over half of respondents on the survey said that project management is a roadblock to getting work done or simply an administrative position. And given what they found, maybe there's some truth to that. Another question they asked on this survey was about dealing with fires. They wanted to see if there was a correlation between the maturity of a team and the number of fires they dealt with in their day-to-day project work. They expected to see this inverse relationship align, whereas a team gets more experienced this guy. So as a team gets more experienced, no, you're on the other side of this. So it starts here, goes that way. So they expected to see this inverse relationship between the experience of a team, the maturity of a set of processes and the number of fires going down, starting with the least experienced, the newest teams, the most experienced, the most developed processes, least fires. That's what they expected. But they didn't find a line. They found a curve. So the line started with the least experience and the least developed processes and dipped for a while. And then at the other end, where you would expect people to not have to deal with this, they found the line going way back up. So that ended the curve, obviously, as well out of my experience. You know, team of eight, like I said. But as I try to solve problems for my small team, I do try to keep in mind that statistic. It's a good reminder that it's really hard to assemble and work as a team with clients and deliver great projects on time for everyone. And it's the people we're really going to focus on while we're connecting these dots between them, the people, the work, and the tools we use for project management. I'm really convinced that you don't have to spend a lot of money on project management tools to deliver value. Because what happens when you choose bad tools? For us small teams, we are probably sharing tools that have to serve our entire team. You know, it's not like being at a big enterprise level company where your tools are your tools and everyone else's tools are their tools. So we're asking our teams to interact with our tools, like for time tracking or status reporting. So in another survey conducted by a professional research company, EG2, half of respondents said they were unhappy with the software that they felt forced to use at work. Another 25% admitted that they had left or considered leaving their jobs just because of those tools. So now we're not just talking about project fires or simple team inefficiencies. We're talking morale, productivity, and turnover, which are huge expenses for companies. So our choices here are critical to the success of more than just our projects. So where do we start? One of the first things I did as a brand new project manager was order some books. Because it's 1897 and I like books. One of the first books was the Project Manager's Book of Forms. I marked nearly every form on nearly every page as something we should do. My boss was so excited. I typed up voluminous documents based on those forms that nobody understood and that I didn't have time to maintain. I argued pointlessly in meetings for adherence to these processes that I had never actually tried. And what I didn't do, I didn't ask questions. I didn't talk to the team. I didn't try to find out how they work and think about work. And I didn't try to find out what tools they were interested in using and how those might solve some of what I saw as my problems. But I was referring to this heavily marked paper real life book to solve. Once I started taking this approach of actually talking to people, I started seeing progress. People were buying into good ideas, contributing good ideas. Projects still had problems, but not always the same problems. Once I started leaning on my strengths and thinking about project management as a design problem, a communication problem, a people problem, I was able to start establishing a system that could give me the information I need to do my job and a system that my team can really own and grow with me. And as you all know, stakeholder buy-in is key to project success. So here's another example. I want to tell you a few more stories about this point that I'm trying to make, right? So how about the time we signed up for a year of an SEO reporting dashboard before we realized we couldn't bring in analytics data? Only ad words. I remember using a lot of exclamation points when telling Boomer, my boss there in the back, we were good to pull the trigger. And instead of using this tool and having more time for higher-level work, planning strategy, providing recommendations, we chained ourselves to an expensive tool that only did half of what we needed and we had it for an entire year. I didn't push the team to really dig into this tool before we said go. I didn't take the time to understand the problems that the tool was supposed to solve and the nuances of our circumstances that affected what we needed the tool to do. And that's where we start to come into this design, this project thinking about what we do as project managers. Let me tell you another little story about the before time when I wasn't a project manager but managing at a small knitting shop that used to be outside of Salute in North Carolina. There we had a similar-ish set of tasks to what my Big Boom team does, if you can believe it. We were doing support, helping people with projects and teaching them new skills. We were conducting projects like mostly internal things like inventory, building displays, that kind of thing, and we were doing sales. Sometimes helping make selections and decisions but also literally running a register because it was a store. Usually one person helmed the entire operation from open to close. One of the least useful things we did over and over again every day was interpret product tags for customers. Meters converted to yardage, determining yarn thickness from its weight, fiber content, washing instructions. Yarn companies all have a different way of presenting this information and people don't want to stand there and take the time to figure it out. If they can't figure it out, they won't buy the yarn. But providing this information by me walking over to the shelf and reading it off a product tag wasn't actually helping sell product. And it was derailing the activities that actually did. But it's something that people needed. People needed that information to start making the decisions that actually led to those sales. It was my job to provide the information but not my only job. The tools that used to solve this problem weren't exotic and the idea isn't original. I just made shelf tags with big lettering that answered the five most commonly asked questions about each variety of yarn that we carried. I added some color to make them stand out and people quit asking those questions because they could answer them for themselves. They'd come to me with more complicated questions and actual ideas by communicating, by taking the time to talk to people, take note of the types of things we talked about and the context of those conversations. It was easy to identify basic needs that could be addressed with basic tools. But what do we do when problems and their solutions are bigger than what we can accomplish on our own? Because we're project managers. We're not just by ourselves every day. The point is to coordinate these groups of people and help them work together. And that's where we have to start talking as a group and understand how we interact as a team, what kind of team we're on. It was important for me to understand the distinction between my eight-person team that wore different hats every day and a team where maybe there are more or fewer people but the roles don't really get shared. Once we could start to talk about those things and understand them together, then the solutions we could come up with weren't just like sign up for this service or find this tool. We could solve our problems by using the things we already had. So that being said, you know, tools are cool. Man, they're out there. Let's talk about them. What makes a good tool? A good tool makes sense to your team. They use it as often as they need it. Not having it is more expensive than having it. It does the thing it's supposed to do. And a good tool usually gets better over time. Someone, whether it's your people or someone else's people, are working on it to make it better. So one of my favorite stories about tools is another story from outside of my life at Big Boom. And that's my husband over there looking embarrassed. So this is going to be fun. My husband and I have several different coffee makers. We have an arrow press, a French press, a pour-over carafe, and a couple of in-cup strainers. What we don't have is a drip coffee machine. We tried four years to have a normal 12-cup coffee maker. While we can keep a lot of things clean, like adults, a coffee maker isn't one. On paper, it's not that hard. I still have a strong feeling that any adult should be able to maintain one. And it's handy to be able to make a big pot of coffee for sharing or for storing. However, this coffee machine for us was always, always dirty. We would both avoid it until it reached science experiment status. We talked about it. Who should be responsible for what when assignments were made? In conversation, everything seemed doable. But in practice, it was a nightmare. And it was important to us to resolve this. We wanted to feel comfortable drinking our coffee and making it for other people. So finally, I bought the arrow press. The arrow press is almost impossible to not claim because it's a couple of tubes and like a rubber washer. And you push the grounds through one tube with the other tube. Everything gets cleared out just by using the thing for its purpose. And that's something that I feel like holds an important lesson for project managers. Consider the goal. Is it to do everything a PM should do and make your team go along with what that looks like?  If you can state your goal plainly in human terms and relate them to the needs of your team and your clients, then you'll be better able to pivot and find the tools that do what you need them to do that don't get in the way of achieving the actual goal. Oh, I do have a photograph for this section. Look at all those tools. But to get back to our PM tools, our work as project managers, lots of people use Google Drive and Google Docs, right? You probably already do. We use it for internal file sharing, collecting content from clients, and more and more for setting up and sharing essential project documentation. Since it records individual access and can save named versions and you could add your own templates in addition to all the other cool formatting and sharing stuff, it's a great option for important project documents. When we started doing this, I was fresh out of reading the project manager's book of forms. It was digital paper. I could use as much of it as I wanted. I tried to get all the way down to brass tacks and those scope docs. They were seven to ten pages long. Nobody read them. They didn't understand them if they read them. Even our team found them completely baffling. No problems were solved. Clients still wanted what they wanted. Questions and loopholes still existed. Assumptions were still made by all. Communication was not made easier or better. So now a project scope for most of our projects is a page. The first paragraph is a summary of the client, the project goals and the agreed approach. The rest of the page is a simple list of what users will and won't be able to do on the site divided by user groups or user roles. Design scope gets handled in the estimate and then through the project has change requests. There is a second page where I can keep running notes on the budget and on those change requests and clients can see this entire document anytime they want. But if I hadn't taken advantage of the tool I had that was already available to me and pushed it to provide this complicated solution and listened to the feedback that I heard and observed the human behavior around it, I wouldn't have known how and what to pair back if I had leapt into a complicated software solution instead of using the simple tool available. We might not have had the flexibility to change course when we needed to. Change would have been that much harder. You know, like that SEO dashboard we were, I was so excited about. Switching gears for a moment, still talking about tools. Who likes reminding people about things they're supposed to do every week or heaven forfend every day? Oh, boomer. That's why we love you. Does it make you feel like the office mommy or pop-up? Well, get you a robot and start automating some of those highly repetitive reminders. I started using a site called automate.io to handle basics like project monitoring since our task management software is kind of all or nothing on the notifications. When we started formalizing our client support system, we divided up the week into shifts and everybody, including myself, signed up for a couple of hours a day, right? So we're supposed to be handing off the shifts and communicating about, you know, tasks that are coming in and all that good stuff. The people are people. It was a new system. People get lost in their other work. Things happen. Shift came and went unremarked. But nobody wants to be the person walking around reminding people to take their turn answering email on the telephone. I didn't want to be that person. Heck, sometimes I need reminders, too, you guys. So I have a little automate.io bot that checks the calendar and slacks people right before and at the end of their shifts. People appreciate the reminders. Shifts are getting covered. Problems are handled. Work gets done. Automating this releases me from being the reminderer, so I can be a person, too. One of the effects of that kind of micromanagement is that people who seem to wield power get held up to the demands they make by keeping myself responsible to the same system as everyone else and using a tool to help keep the system moving. I didn't have to be or pretend to be perfect. When you're trying to solve these people problems, it's easier if you're a person, too. And now I'm going to have a long pause for a drink of water. How's everybody doing? Is that a good word count? Great. So much breathless excitement in the room. So speaking of automation and continuing our discussion of tools, excuse me, I can bang out a pretty good email. I'm not going to lie, but it's a pain to type and retype the same things over and over again. Remember all those details that need to be included, especially for important things like project milestones or team member handoffs for not already using canned email responses, email templates to, oh, man. I don't know what is living in the back of my throat now, but it's not good. Does anybody have any questions at the moment? Oh, that's fantastic, because it's got like... It's awesome. And the free, there's like a free level that's pretty good so you can get in there. Oh, yeah. Yeah, I kind of hate that beer. Oh, really? It just seems so much more straightforward. Yeah. Yeah. Yeah. That's an eternity on the Internet. So we're never going to do it again. Yep. I feel like it needs like 30 days to automatic, you know, capital exclamation points. Does that help? That so helps. I feel so much better now. You got it. Yeah, yeah. That's an excellent question. I will say I don't have a good tool just for that right now. Also, as a new PM, just everybody else just like show yours for a minute. Yeah, he was asking about utilization. So we're talking like workload and like resource management. It's interesting because our task management software, Asana has started broadcasting that they have workload planning now, but I haven't explored that yet. Good question now. Thank you. Maybe it's the wrong time to talk about how I'm a power user after admitting that. I don't know. I don't know. But I do like to really explore the things that we do use. I like to know at least a few keyboard shortcuts and all of my desktop apps. I click buttons. I look at menus. I investigate settings panels. And maybe you think that's a little ridiculous. Probably you don't because you're here. But tomorrow at the happiness bar, come find me. And I'll show you the pointless cap on keyboard shortcut in Asana. It's great. Harvest, our time tracking and invoicing software can also record expenses and automatically include them on invoices with dates and receipts and everything. You know who wasn't using Harvest to automatically invoice and expenses? Us. Perfect solution right there in a tool we were all already using. It is worth it to spend time with as many of the tools you and your team are using already as you can, especially if you're thinking about pursuing other tools. Also, keep an eye out for blog posts and go ahead and sign up for some email updates. They'll let you know when new features are rolling out and how to get or find them. If they don't, then you know you may outgrow that service or software eventually. But you'll have a better sense of how far you can push the thing that you're already using. This is going to be great WordCamp TV. OK. So we talked about Asana briefly. We've been using Asana for, I think, at least five years. It is task management software that's recently started evolving to be more of a project management solution. Several times, past big boom managers had tried to keep a master client list in Asana. Basically, a project set up just to list out each project or active client. There wasn't a way at the time to get that kind of information out of Asana without either doing this kind of hacky thing or building something outside that used the API and pulled information out of it. So this project of project never really worked, partly because it was not just active projects. It was all clients. And those two lists, projects and clients, they should do different things. They should be different things. The alternative to the project of projects was to prep a list for every update meeting, which takes time and multiple team members and turns those meetings into status reporting slogs instead of strategy or problem-solving sessions. Either way, I made my project status reports. They were time-consuming and siloed data away from the rest of the project information and the team.  So when our art director, Sarah, suggested setting up another project of projects in Asana, I was like, no, we've tried that. It didn't work. I don't think we should do it. But Asana changed since the last time a BBD project manager tried to do something like this. And our team had changed. So we tried it. And it's kind of working. We update project statuses and their individual Asana projects linked to the latest status in the current project list and only list actual projects. We use Asana's built-in custom fields to show things like budget status and priority. Boomer doesn't have to wait half a day for updates from all project leads to roll in and get compiled. It wouldn't have happened if we weren't willing to respond to change and take note of how the tools we do use evolve and update. Sometimes it's worth trying something again when you know that the paradigm has shifted. So I know I already talked a little bit about our support work, right? And we really are doing a lot to try to make that as easy and awesome as possible. So now that we have the system in place, we've started building some internal company tools based around WordPress sites or plugins. But I like our maintenance contract system because it was fast, easy to build, and solves more than one problem. All we did was build a gravity form on our site, add a plugin that can render submissions as PDFs, and attaches those PDFs to a notification email. Now clients read through our terms and sign and return agreements at their leisure without printing an, oh, my God, Boomer. Oh, is that smearing? Oh, man. Anyway, y'all were about to be real sad when I ran out of water. Now clients can read through the terms, sign and return the agreement at their leisure without any printing and scanning. We're not filing hard copies unless we want to. Our support coordinator, who's over there in the red shirt, doesn't have to mess around with, you know, word templates or, you know, all those other things. We've got a built-in list of who signed on and when. And it's not always a great idea to try to build your own tools. Anyone who's thought, I can make a CRM, I know how to WordPress, knows that it's a huge challenge. Sometimes there are reasons to let other experts make something and then keep on working on that. But you can use your expertise as a PM to think about the business case, right, for making a tool that you need if the right thing isn't available. And DIY it if it makes sense. But I think not to, I think my favorite project management tool, the thing that I come back to the most is communication. And I think that to become a good communicator, you need to practice, right, you need to talk to your team and listen. But also, you know, there are ways to learn about communication and get better at it by deliberately, you know, incorporating some new ideas and thinking about it differently. So making things happen is a great book if you're new to project management or if you want a refresher in the basics. And it is a project management book, right, but a great deal of it is spent talking about how to listen to your team, how to, you know, remember to walk around the office and see what people are doing. Because sometimes people don't tell you what problems they're having. And it puts those communication skills in that specific context, which is really helpful. In a more general sense, I really enjoy another book called The Crucial Conversations that has more, it's more, it seems a little like a relationshipy kind of self-helpy book. But since we are kind of in the middle, right, of these things that have great meaning and emotional importance and business, you know, importance to all these people, you know, our bosses, our clients, our team that's spending all this effort in making these things, we end up in charged conversations more than I think we realize. And when we step back from that and have some deliberate tools, like a framework for actually approaching that, we can better manage how we move through those conversations and get what we need out of them. So we've been talking about tools for a while now, right, and we talked about some specific, specifics, talked about Automate, talked about Asana, we talked about Harvest, we've talked about, you know, some learning resources, some learning tools. Basically, use the tools that are around where you're working, keep tools where you work. The tools are probably already where you're working. You probably just need to look at what you already have.  You are a resource for making things happen as much as any of these software tools that you are trying to employ. Sometimes data is bad. And sometimes it's bad because the projects were bad. It's, you know, it's objective judgment of performance, your performance, the team, the clients, because they're also performing. But sometimes historical project data, like the information that is left when a project is done, is bad because things are missing, or you realize that the way the data was structured doesn't actually tell you much about why a project went well or poorly and why. As project managers, we deal with both types of bad data. And one of our functions beyond managing active projects is interpreting information about past projects to make predictions about future ones. Lessons learned, you know, after a project is over, is really helpful. It can be much more informative to fail than to win. Bad projects ramp up skill sets really quickly because they make the gaps in your knowledge really obvious. But even these good, bad projects can still leave you with actually bad data. So what do you do when you realize you're dealing with bad data and not just good or bad projects? Well, you do the best you can with the information you have. Bad data is still a tool. It's a way to see where people problems have cropped up and a chance to change course. Forecasting project work is hugely problematic under the most ideal circumstances if you've gotten really good at proposals that accurately predict the work, the schedule, and the actions of the client, please let me touch the hem of your garment later and appeal for your blessing. So do the best you can with what you have. Then communicate with your team about the problems you're seeing in the data and the work. Use those conversations to make adjustments or changes. It sounds simple because it is. It's normal to realize that the way you thought something would work didn't. It's frustrating when it's coming from inside the house, but it's normal. Oh, I do have a picture. Yeah, he's got some bad data. It's easier to point to something that's clearly not working and convince people that something needs to change. It's really hard to pull up a good idea just out of the blue and get people on board. People don't like change. And as a new PM, you don't always have the street cred to get people on board with these strategies without that problem to point back to you and say this is why we're doing this thing that we're doing. But when you're dealing with bad data, what you can't do is be complacent or pin blame. It is what it is, is the death now unless it's paired with active plans for change. Don't mistake blame for accountability. Blame is finding a scapegoat and a reason why nothing needs to change because X, Y, Z is at fault. Accountability is stepping up and saying, this can be better. Here's what I think, what I can do, what I've already started doing, what I've asked the team to help with that will make it better next time. In that vein, we use Harvest for all our time tracking, right? In Harvest, there are projects which is a way to group track time together for a specific purpose. Sometimes maybe it's just an open project that's like for ongoing support. Sometimes it's a Harvest project that contains the work done on an actual project. And you can set up a collection of tasks and rates that get automatically added to all new projects. And this is a great way to get consistent visibility into the division of work across multiple similar clients or projects, right? If they all share these same places where time is being recorded, then you can go back, thank you, and look later at what you have done across more than one period of work or time. Our Harvest tasks were a hodgepodge of ideas that came from different people at different times over the company's history with this tool. What should have been the greatest source of historical project data was kind of useless for forecasting. When I had to produce my first sort of year overview of project performance, that was more or less doable. You can find budgets and see, literally, did we meet the budget, did we meet the schedule, all that good stuff. But I couldn't tell why projects were good or bad in that year. I couldn't give a narrative for how projects had played out. What I could do was use that opportunity to highlight in a tangible way how the data had failed us, the human problem underneath it, and propose a solution. Everything on this project build was clocks under the same category as design work because there wasn't a clear task set for development. No one ever asked for clarification or reviewed the entire project task outside of Asana. This was the kind of conversation we had to have during that meeting. It was not fun. But it highlighted the places in the process where tackling people problems could result in better data, better reports, and better proposals and forecasting. It took us some time to get a good set of harvest tasks, right? But eventually, being flexible, responding to results in a collaborative and thoughtful way, committing to seeking and making tangible changes rather than submitting to change by entropy, it was a project management tool. And I've got two minutes. So, what I'm going to do is say, I was actually pretty surprised by how much I enjoy project management. All my training up to two years ago was for making things and not managing anything. So, even though I'm up here, and normally this is the time when people say, I'll be at the happiness bar, if you have any questions, if you have a session, I want to turn that around. We don't have much time here today, but I'm checking into sickbait tomorrow morning. And I would so love it if anyone of the people in this room who have been doing this way longer than me just come and let me ask you about what you know. So, what I'm hoping, aside from, you know, helping me, please help me, is that you'll have some things to think about to make your own tools work for you without having to spend money on new things that maybe don't pay off. And that's it for me. I'm Janine. That's my cat. Have fun the rest of the afternoon and an awesome work camp.