scala.bythebay.io: Dick Wall, All you ever wanted to know about "for", and more...
Recording: scala.bythebay.io: Dick Wall, All you ever wanted to know about "for", and more...
I you yes so there is a sound which is playing but very very quietly so quite the account Aaron it's the four song and originally this was called everything you wanted to know about four and more we did this talk Josh surrett and I wrote this together and delivered it at scala world and the title was deemed too boring so we had a competition and the winner was for what is it good for absolutely nothing say it again so sadly josh is not able to join me today it's a lot of fun working with him presenting with Josh but he has a lot of stuff going on and couldn't make it so it's just me I apologize if you're expecting their that you lacked hopefully I can pull this off myself I may at times take Josh's part for comic growth but we'll see how that goes my name is Nick wall um I decided having one job was too easy so ended up getting two of them in my in my professional life I do skull of training with escalates often if you like what you see today baris in mind for scarlet raining and then my day job is with company called sebo technologies we are hiring they asked me to say that we do very interesting work the kind of thing you're going to be seeing today so um hopefully yeah yeah all right oh my god there we go okay so for what is it good for for is a very interesting and sophisticated and powerful and flexible language construct in Scala and when I mentioned wherever I don't know how with josh tonight all probably once a week at that at the very at the very least and we're always riffing on stuff and we sort of came across this one together it was it was like you know there's a bunch of things that I i show my co-workers that they can do in four and they're completely blown away by that and he said I've noticed the same thing we should do a talk on that so this was a bit of an experiment and one of the things that's different with this talk compared with a lot of the other ones that we've both done in the past is normally a talk has a level like it's beginner intermediate advanced this one is a super narrow vertical thing it's about four and it will run from the very basic principles all the way through to monett transformers and then some co monads at the end so I think there will be something for everybody if you get a bit lost along the way don't panic not you're not you you're not going to be tested on this at the end or anything this is just hopefully some but everybody will get something to take away from this I'm particularly pleased that when we did this at scala world mile saben came up and said afterwards I learned something in your talk and I figured job done at that point apparently everybody took something away that they didn't know what he learned was mostly useless but you know all I thought it was he got very excited about it so that's that's good okay so people arrived imagine seen people arrive at scala for the first time and they see for they see this keyword for and they're like I know what that does I know exactly what that does believe me I train a lot of people I see this this pattern all the time they think for it's about looping I can do things like this right so I can go for i from 1 to 10 print line hello world and i get 10 hello worlds clearly that's about that's about looping and then they you know you can you can use the I if you're not using the index you can use the ubiquitous scala underscore which means i don't really care what this thing is just match anything right so you can do this some people haven't seen that notation before but it just means i'm going from 1 to 10 but i don't really care about that value so you know make it happen don't give me the valley you can do more than one thing by putting things in curly curly brackets here I suppose it's worth going into I don't have a lot of time not as much as I normally do but main difference curly brackets and parentheses in case you didn't know in Scala often interchangeable the main difference between them is you can have commas inside / ends and you can you get semicolon inference inside of curly brackets that's a good way to remember it so often you'll see curly bracket around the second block in a four you can also have it around the first block unifor and you'll get semicolon inference if you do that what's actually going on when you do this is if I run that will see a bunch of stuff coming up what you're getting here is you're getting one to ten turns into a sequence called a range it's actually a lazy sequence in scarlet and feel like that's too low hopefully that's better and what the four is doing is visiting each of those items in turn and doing something with it alright if you put two of them together let's do this again you can see the same thing by doing one to ten for each and in fact you know lesson number one may be a bit basic this is literally the same code okay i'm going to show you that in a second but when scholar sees a for expression it d sugars it into calls two for each map flatmap with filter and valve effectively this is what happens the scholar compiler does this and I'll prove that to you in a second so this is literally equivalent code the code above by the time it gets through parsing the parsing stage of the compiler will actually look something like this I'll actually look a bit uglier than that because there'll be some dollar signs in there and other stuff that scholar likes to to jump in with I want about something like this so this is a bit more interesting we've got 24 i from 1 to 5 and from jay from one to five for jay from one to five in the same block what's that going to look like well d sugared this comes out to look like this one to five for each I 125 for each J and then print on that number of times okay so i'm not going to labor this a whole lot just i think it's interesting so far can't remember that one at the end was four but i'm not going to spend time on it because i think we can move on quicker okay so what we've seen so far is a for statement it is statement because it has no useful return type okay in order for that in order for this stuff where is it oh no don't don't die in order for this to do anything useful it has to have some kind of side effect in the in the block otherwise you it's going to heat up your CPU and that's about all it's going to do there won't be any observable any observable change from it and that's because it returns unit in Scala which is equivalent to void it means it has no no interesting return type it's just not it's giving you nothing back so pretty quickly people realize that that's that's poor style and a functional language and they discover what they call the yielding way how many people are actually old enough to understand this reference in the room okay there's a few June there's a novel called June and there's the thing called the weirding way in gene there's a lot of puns in this because josh and I when you put us together it's like some kind of critical mass of puns they just seem to build and eventually explode so a yield looks very much like a for a for statement except now it becomes an expression you now have the four and you have a yield keyword suddenly this thing is functional in nature it returns stuff instead it is much much more useful and much more functional as a result so we can do something like this instead of printing out the squares now we can actually yield them and what we'll get back is a vector in this case it's actually an index seek but a vector of 14 9 16 25 blah blah blah I think this is worth a quick mention because of the way the scholar collections are written for and the D sugaring that that happens to fall behind the scenes when you start with a particular kind of collection it will attempt to give you that same collection back again if I started this with a list and i did a four and a yield I should get a list back again okay if I started it with a vector I should get a vector back again I started it with a range and arrangers a little bit more unusual in that it is an arithmetic progression it actually behind the scenes isn't materialised it just says I start of one and then I add one to it and then I had wanted that and so on so that is actually something that then cannot represent a square for example I suppose it could if you really wanted to get into you know some some mathematics there but Skyler gives up on that so what it does instead is it goes back up the call hierarchy and finds the least upper bounds of a type that is suitable for what it needs to get back which in this case is a vector so it actually says I'm starting with a range I'm ending with a vector i'm going to give you back an indexed seek because an index seek is the superclass to both range and vector okay but usually it will give you back what you started with you can do some other things like this useful thing to do is to know that there's a to map so if we yield I and then to the the arrow which creates a tuple to the square I get but I get back then a map of the squares and so on so far you're probably thinking gosh i have really wish i hadn't come to this this is all so basic and I'm learning absolutely nothing so I'm going to kick it up a notch at this point this turns into have I got them down here or is it on the next probably on the next thing let's just show you anyway what this turns into behind the scenes is where did my windows go Oh some really cool stuff so we saw that four turns into for each right when you use a for yield block you get a map but you actually get a map for the first thing when we do something let me show you the let me show you the my yield notebook bring back my yield notebook there we go when we do something like this the first thing they're actually becomes what we call flat map then the second thing becomes a map and that is because if we were to run this otherwise if it was to do map everywhere you can work this out for yourself later you would actually end up with a sequence of sequence of things right the it would it would map over the first one you get a sequence but it would map over the second one you another sequence which gets embedded in that so we have this thing called flat map that is meant to stop that happening to prevent that that explosion of nested nested things and the rules are actually very simple all of these dereference arrows in the four in the in the fall block get turned into flat map except from the last one which gets turned into math okay that's kind of how it does it does flat map flatmap flat map flatmap map and i want to show you that so so you'll believe me so this might be the first time some of you have seen this in Scala let me show you this show phases anybody done this before seen this this is how the Scala compiler works what actually happens is there are a number of phases 25 right now and what what happens is the Scarlet compiler starts off as all compilers Dubai tokenizing and parsing the code but then it ejects something called an abstract syntax tree and then abstract syntax tree are cash real inside baseball here is actually what we call an algebraic data type it's a bunch of case classes and the Scala compiler is effectively a great big pattern matcher it gets these case classes that represent the program that you've written and each phase up until the very last one which generates JVM bytecode works on those patterns and changes the patterns it morphs them as it moves through the Scarlet compiler this is interesting because this parser is where a lot of interesting or you know early processing happens in the Scala compiler and one of the things it does as it says here is once it's turned the source into an abstract syntax tree it performs simple d sugaring now we can actually stop the compiler at any point along its way and print out what the abstract syntax tree looks like you can do that like this so if I look at for expansion one scholar okay this is a simple for expansion of i from 1 to 3 j from one to three k from one to three yield I times J times K let's compile that dash X and we're going to do print parser so stop after the parser stage and print out what you've got for expansion one that's Carla okay well that was slow okay so the line I want you to look at is the one that says molts here and you'll see that I wasn't lying to you it now says one two three flat map I goes to 1 2 3 flat map j goes to 1 2 3 flat back odds once three map k and then it calculates the result ok that's the D shivering that takes place this happens to all four expressions in Scala okay so no don't cancel cancel I've apparently opened up too many things leave okay so that's yielding so this is the next progression people go through so we've shown you how this thing d sugars people say well for is obviously about looping because that's what they've come to it from and this is somewhat of a shame that for was chosen for this because for carries so much baggage from other languages house girl has a similar construct to this called do i do also gets associated with leaping a lot of the time I'm you know as it as it happens but what I'll tell you right now is for neither for nor do are actually about looping do in Haskell not do in Scala doing scholar is actually about looping that makes perfect sense to me sorry if that was coming at you but quick but what I will tell you is for the for expression in Scala its relationship to looping is incidental its own it only appears to be looping because of the type of thing that it's working on okay we can show you an example of this an option okay options are this kind of box that can either have something in it or doesn't have something in it and lo and behold option amongst the things that it has it has a for each it has a map and it has a flat map on it this means we can use in and a Forex Russian and when we do people say oh well it's just another collection it's like a collection but it's got like at most one things in it so I see people wrestle with that concept so here's an example and i want to show you this as well because this is a nice pattern that i want you to remember after this here is something that just multiplies three numbers together shouldn't be any surprise that if i turn those all into options okay here's the original XY said result is x times y times said if i turn all these into options all i have to do to make it work now in that space is dereference x y&z in a for expression okay and then take the same piece of code that i wanted to run on x y&z and move it into the yield that formula will work on any kind of container that works with four you can just be reference things move them into it move that into the yield blog this is true for futures this is true for any of the monads you'll deal with just take that code dereference things use the same code that you were using but use em in a yield block nice easy formula for people to remember and lo and behold if we run this we will see Owen the first one I should run first so this one gives you back when it finally runs gives you back some of six now what's interesting here is that we can write this code Neil assuming the happy case this is another advantage to these things and so we can say x times y times Z or Z and if one of them is not an expected value let's say we have none for example but container itself knows how to deal with that situation it does this we could go into this but we don't have time it does this through its definition of what map and flat map are okay as you go through a map or a flat map operation with a nun you always end up with a nun so therefore the whole thing becomes a nun they're defined like that there's no magic there it's just that it lets you concentrate on the happy case and takes care of the sad cases for you so people say when they first see that they're like oh that option it's just like enough it's just like another collection you're cheating me and then we show them that it works on futures so same example but this time we're going to bring in let's get these running here and we'll do a future one so this is cool I'll do the future and we will show when it runs there we go at first it will tell us the the future the value of future is none that's because it hasn't actually been resolved yet I've made it sleep for 10 seconds Victor clang will kill a puppy every time somebody puts asleep in the code so don't don't do this at home I got special Victor permission to do this but if I wait the requisite amount of time I get the answer again now that all happened in a future a future is definitely not any kind of collection right it's a deferred operation it's a deferred execution it's happening it's it's a promise of something that's going to happen later so it once again it just works and it's the same formula we just took the thing that would have been written outside of this we do reference the futures now we did oops sorry we did the same thing in the yield block but now we have non blocking asynchronous code that's the beauty of this that container did all this clever stuff behind the scenes and made it so that this thing it returns immediately whether it's done or not yet and the whole thing becomes a synchronous very powerful to be able to do this so then you say well clearly fours are not about loops and that's the place where you finally reach for creamy enlightenment and the whole world suddenly shifts about an axis you're like wow this thing's really cool so the philosophy over 4 is basically work on what's inside and let the outside take care of itself ok York until you're actually splitting concerns you're letting a container dictate how it's going to work be it deferred execution or a try is another example of this where it could be exceptions it knows how to pass the exceptions forward if that if that's the state it's in what's my happy case the sad cases that is decided by the container and the logic matters but the context does not matter at least not yet okay now we get into the pun section of our talk this is this is all on Josh I have no I no hand in this he decided that if we could have the three hours of Education reading writing and arithmetic of which there's actually only one of those that starts with an R he decided we could do the same thing with fours for a G so we actually do a bit better but we have what we call the the 3 g's or actually the 4 g's of a 4 okay there is the for block which is the setup for your for your for expression it has three things that it can do it can have a generator which is the arrow that means take something from inside of something else and use it it can have a guard which is an F and I'll show you one of those in a minute and it can have an inline assignment okay with a G the gene may be silent but it's still there and the inline assignment is somewhat like a valid lets you put something into the for the for setup and then finally the yield or give block because that starts with aji gives you back the the payoff to this set up okay all right generators some things you might not know about generators generators are pattern matches there's another place where pattern matches show up in Scala let me show you one of those a lot of people are surprised about this case class person named string whoops string age int and if I say Val p1 equals Harry person Harry Potter and here's a scary thought I think he would be 32 now judging from when the first book was written so p1 Harry Potter now I can say Val person of name and age equals P 1 that's a pattern match in Scala okay a lot of people don't know that that val is actually a pattern match so is the left-hand side of a forex of a for expressions generator block so you can do things like this wrong window you can do things like from a map ki kamar value a map behaves like a effectively a sequence of tuples so we can unpack the key in value from the cheap or two right there in code very nice idiomatic way of iterating over the keys and values in a map right there lots of things that you can do with that and I mentioned that it's consistently tight so I'm not going to not going to hop on that but basically if you start with a list you should at you most times will end up with a list if you start with option you end up with an option if you start with the future you end up with the future now here's a role you can't mix the things in a set up block okay and we're going to hit that in a minute that's that's how do you how would you mix an option and a future now if you now that you know how it d sugars try writing that as a set of maps and flat maps sometimes and you'll see the problem the type signatures don't match up it violates the type signatures of map and flat map if you try and mix a list in a future or an option and future or something like that okay one last thing we're going to look at is guards oh no that's actually in line assignments as well guards are a way of saying you know that back-up plan that this container has when something goes wrong in other words it's a nun or the future has failed or the tri is an exception the guard will short-circuit to that statement okay so we can basically say you know 4x from one to ten for wife and once ten this is a this is a range or a loop based operation if X mod 4 is less than Y mod 5 what this turns into behind the scenes is one more a special name that it uses which is with filter calls something called with filter you can it's called with filter as an optimization you can actually implement with filter pretty easy in terms of filter if you ever write one of these yourself it's not it's not that hard to do but you can also use the width filter to optimize things and do things lazily if you prefer to do that which is one of the reasons it's there and then an inline assignment so at any point in the code let's bring up the the examples for this because I think they're a bit more descriptive here's a guard so for iphone one to ten for jay from one to ten if I mod 3 equals equals zero or jmar three equals equals 0 K from one to ten and so on now if we down here decided we wanted to check the multi multiple one of the things we can do is we can say if I times J times K mod 2 equals equals zero then yield I times J times K but this means we have to do that that computation twice what we can do is just an inline assignment in there okay it's different from a generator it doesn't map or flat map it just sticks a vowel into the hole d sugaring process and this ends up looking something like this now when you do this it has to pass forward to things suddenly it passes full with the K that we've just that we've just got here in our map and it also passes forward the multiplier I think Rob Rob told me there was a mistake on this slide and it's quite possible there is but I can show you that it does in fact do this pattern matching and I will do that in a second so that's how the thing gets past forward actually gets to pulled up and pass forward and this was the thing that miles actually hadn't really thought about before and we both in a conversation afterwards had this sudden sort of question that hits us both at the same time which is why happens if you get more than 22 of those things so we wrote it and it turns it into a tuple of tuples at that point so it does cope we found that out on the day it will cope with more than 22 things in there so some other things you can do with an inline assignment though I don't this is one of the gems is remember that underscore where we don't care what something is well we can use that we can put an inline assignment we can call any code we want to on the right hand side of that any method we want any side affecting stuff that we want to do maybe we want to print a diagnostic out like this that's one way you can do that put a log message in there to help with debugging all sorts of things like that okay obviously it's not very functional to stick side effects especially in a for it in a four-block that's going to cause some weird stuff to happen unless it's just a diagnostic like this but it can occasionally be quite useful to be there to be able to sort of drop in in the middle and find out wow what state of things are so okay oh and I promised I'd show you what that looks like so let's go back out here I'll show you one more trick along the way which is using ammonite anyone who's ammonite yeah okay ammonites got some neat features and one of them is this so let me go back first of all let's put in a fairly lengthy that was the example I did with the inline assignment and then I'm a knight include wow that's slow come on and then ammonite includes a nice little macro called D sugar that you can use and you can dump the same code into D sugar and it will stop and print out the abstract syntax tree just like the compiler does so that that is what that turns into you can see the pattern matches here it's doing a case of tuple to of K and molt and so you can see how that feeds forward through the process be if that comes up with filter but you can see again just D sugars into those calls so the thing about that is you can use for in your own code by supplying for each map flatmap and with filter with the you know with the correct signatures or even the incorrect ones and if we have time how am i doing another 20 minutes I think we might we might get to the not quite how long that one's ten minutes fast they all right okay well I gotta move then all right so this is where i'm going to channel my very very good friend Josh things that have flat maps and maps while map is something that lends itself to being called a functor and a flat mat I think there's a talk on that right after that this talk in this room and a flat map Lee lends itself to something called a monad scary names for and utterly meaningless names by the way for something that there needs to be them now the thing is as just likes to say it's a bit of a corruption to say something is a monad because the correct technical way of saying it is that something has a monad now in Scala that's become a bit more muddied because flat map and map and things like that they're actually implemented on the classes themselves and that's house that's how scholars for expression uses them but you can formalize things by actually creating a monad trait if you want to do that and our moment rape is going to have its actually a monad funk term all monads or functors but we're going to have an apply we're going to have a flat map and we're going to have a map and this is going to be for any type M that we won't put so we could write one of these for lists we could write one of these for option we could write one of these for future and once we've written that we could use this monad in a for expression ok we can formalize it like this now why would you want to do this when it appears to be easier I think maybe I've got just enough time to cover the the type signatures here type signature for flat map is pretty simple starting from some M of a and given a function that goes from A to M of be the result will be M of B that's the flattening part because it doesn't become em of em of V the map is starting from mfa and given a function from A to B we still end up with an M of B now that's a map but if you combine them together you'll see that you actually migrate through the system staying in the in the type space of em everything gets past forward as an M as it moves through okay and here's an example of just you know pulled out of the air some github API call that with that we're doing and in this case we're using that context the a particular context for a sequence of project of something now why do we do this why are we doing this with context of underscore well if we have a monad for context of underscore we can actually swap in what we want to use his this is fairly this is fairly flexible it also comes at a fair amount of implementation costs don't underestimate the amount of work to make this up to make this work but what you could do is have a synchronous and an asynchronous implementation for this that is swapped in at compile time basically and you can say for testing purposes I'm going to run this using the ID monad which is basically just return itself just run it run it in the current in the current thread blocking all of that stuff make it easy to debug and then when you're out in production you can swap in a future context for it and suddenly everything happens asynchronously so that's a that's a nice thing to be able to do and if you want to know more about that josh has a great resource up on github intro to FP that you can go and read up all about that other types that can have monads either state validation many of these I'm not going to dig into them because I want to get to the X exciting part so monads don't mix okay it's very very bad the and and you can see the reason for this if we go back to hear if we start with an option pretty much the only place that we can go to as an option and the flat map requires the same M it has to be another option okay start with the future this type signature is only going to be satisfied by another future this is the reason you can't mix these things okay so now there unfortunately their attempt to make things easier there is an implicit conversion from option to sequence that allows some mixing this is very confusing for beginners some cases where option can be slammed into the middle of a bunch of sequences and it still works and then all of a sudden you add another sequence and it doesn't anymore and you see it you know in this setup you see it with something oh I haven't haven't run my begin a bit there we go let's get that running and once that's Ron get this running so if you write it out in the way that we that I've been telling you to do so you know in your mind flat map flatmap flat map map the problem actually exists right here from the flat map of option to the flat map of see the problem here is not this is not the problem the first one because an option can be promoted to Asik implicitly and scholar but it doesn't happen the other way around obviously and a sequence can have more than one thing so you can't make an option out of a sequence implicitly and so what happens is when you get to this point here it says you're trying to map flatmap Asik into something that's expecting an option there's no implicit for that so that's a type error okay how do you get around this quick answer is stick to seek on all of your options when you do this whether it needs it or not just go ahead and do it it makes it much easier than having to think about it okay that's the that's the quick fix there all right so what happens when when my notes don't mix well sometimes you want to cross the streams right sometimes you're dealing with a future and something else gives you back an option and maybe get a list from somewhere else and now you're like damn I really want all these things to work together somehow how am I going to get this to work all right so in the grand tradition of scholar over-engineering I'm going to talk about that solution first and then talk about the sensible ways to tackle it actually I'm being unfair this is a this is a lovely library that Daniel Spiewak road I think it's actually if I was ever going to use these this would be what I do I can tell you now in 10 years of scholar development I still haven't ever had to use a minor transform events has never not been another option I'm sure there are people in this room that would disagree with me but they're usually doing type Oscar naughty stuff that I don't do in my day-to-day work however this is as they go probably one of the best solutions to this okay it's called em and it is a macro based very generic solution to this problem of monette transformers and it really does illustrate the kind of idea of what it's trying to do so the idea where the Mona transformer is you have some monads that are different you can't mix them together so you have this thing called a monad transformer and it exists to provide a common are grouping for all of these different monads so that they will work together and the way it does that is you specify while I'm dealing with a future and an option in this case so i'm going to set up a moan and transform of its future option and then the last thing always has to be based it's like nil at the end of the list so it's the future of an option of something when you do this you get an implicit lift em that will take any of the types here anywhere along here and turn them into one of these ms or one of these ease in this case so we can lift an option into a future option we can lift a future into a future option and we can run the result and what will get back eventually is a future of option no matter whether we started with an option in there or a future in there or whatever you can mix them together at that point and it just basically uses the fact that monads follow a bunch of laws if they're going to be well-behaved the fact that they're following those laws makes this kind of generalization possible I think I've got time to show this very quickly now you know what I'm not going to show it because I really don't have time i'm going to show you an alternative instead back when I was a kid my dad used to have everybody everybody's dad's they're here right and you're in the garage and he's working three minutes he's working on power tools and I'm like that I want to use the drill it's like he hands me this one that says why don't you get used to that one before you use the other one and you know as I've grown up I have one of these now I have my own power drill I also still have a hand drill and occasionally it's faster and easier to use and you really get an appreciation of the materials you're working on and so on and so forth you don't always need a cannon to kill a mosquito so what are some of the other things you can do well a lot of people don't know you can do this okay here's the problem my imports here I'm instead of all futures are all options I've got a future option of future can I do this no I cannot do that it's they're mixing it says you've got a iphone good future I required an option I can't mix those things together one of the things I can do is this did you know you can have a for insider before lot of people don't know that sure you can why wouldn't you so X from f1 or from the future Zed from f3 and res equals in line assignment to get the last one for y from 02 and now we're just going to yield x times y times said they're all dereference now looks a bit odd I'll agree with that a lot of people a lot of people go immediately to my transformers because they don't like the look of a for inside of a 4 if that's not cutting your leg off two or cutting your nose off to spite your face I don't know what is another way to do it and I like this solution is just split them up if it's looking too complicated deal with the futures and deal with the options separately just write some separate methods okay one minute I'm not going to get to the very last one you love to see that another time but the point is there are ways of splitting this up and I think you demonstrate a better understanding of the domain space if you do this as well anybody can follow the instructions on the m site and get something running but the chances are you're not going to understand what you really did just did there it's is going to work you write something like this and you're really working on the code you're understanding what you're doing so the last part which I'm not going to get to so I'll have to be a teaser for another time you'll have to come and see this talk when I've got a little bit longer is the the key thing about for is that it uses it turns things into map flatmap for each with filter okay and so far all of the examples that we've given have aura that I've given have been very well behaved they follow the type signatures that you are supposed to follow 4mon addict behavior Scala doesn't care if you do that you can actually change up the types if you know what you're doing now it leads to some pretty hairy code but you can't there's an example and josh has it out on his site where we deliberately our time we deliberately reverse that turn the turn of sink into a como Ned and still using them for expression by changing up the fact that flat maps function that it takes in returns a different type than the result of the flat map operation you can do that because its name based it's not actually following a type in Scala it's pretty advanced used to do that and I suggest you have a look at the code you won't understand it you won't understand it until you write that code for yourself so if you're really interested I encourage that go and have a look at joshs code sit down and write it for yourself and you will gain the the understanding of what it means to use for in that way and that's all I have time for I'm afraid it's a little bit rushed but hopefully something in there was something you didn't know about for so thank you