Files
hpr-knowledge-base/hpr_transcripts/hpr3681.txt

303 lines
30 KiB
Plaintext
Raw Normal View History

Episode: 3681
Title: HPR3681: Rust 101 Episode 3: Functionally Insane
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr3681/hpr3681.mp3
Transcribed: 2025-10-25 03:48:01
---
This is Hacker Public Radio Episode 3,681 from Monday the 12th of September 2022.
Today's show is entitled, Rust 101 Episode 3, Functionally Insane.
It is part of the series programming 101.
It is the 10th show of Black Colonel, and is about 41 minutes long.
It carries an explicit flag.
The summary is, in this episode, Black Colonel teaches you how to make functions and for
loops in Rust.
Hello and welcome to Hacker Public Radio.
My name is Black Colonel and welcome to Episode 3 of Rust 101.
Now you might have thought the last episode might have been my final episode because it's
been so long since I've recorded anything.
I've been moving, and I've been changing jobs, and I've been doing a lot of other stuff
with life, and I've kind of now in a somewhat stable situation.
So I decided to record another episode, and I got an interesting new audio setup, and
I might go into that in a different episode, but for now, we're making Rust programs.
We're doing the Rust thing, we're programming, and we're doing all that.
I noticed that there was a couple of things that I kind of did poorly in the last episode,
not really in the explanations, but more in what best practices were and stuff like that,
as well as some things that I kind of just wanted to build upon.
So in this episode, we're going to clean up our program to make it a little bit more
in line with some best practices.
We're going to create a function to take care of our actual dice rolling.
And at the end of the episode, I'm going to try to get into a little bit of error handling
and stuff like that.
That might poke a little bit into where I'm hoping to go with this, because I do have
a long-term plan for this series, but we'll see if we actually get there.
Now, starting out with where we ended last time with our program, what we're going to do
is first, I'm going to clean up a few of these things.
So we made all of our variables here, U32s, unsigned 32-bit integers, which is basically
fine and it works for our purposes.
But there is a best practice in Rust, which is a thing where if you're doing unsigned integers,
you can do U size, that's uniform Sierra, India, Zulu, Echo, U size.
And if you're doing signed integers, you can do I size.
And what this does is it gets the default bit size of your integer for your architecture.
So if you're using a 32-bit system, it'll be a URI32 and if you're using 64-bit system,
it'll be a URI64.
This is just kind of a best practice type of thing, because it gives you the most bang for
your buck and it allows you to kind of have a little bit of a different, you basically
you don't have to worry about a lot of like Y2K type bugs as you upgrade systems because
it'll automatically upgrade the bit size.
So we're going to start out by upgrading all of our U32s to U size.
So that's the sum.
U size, the dice is U size, our parse is going to parse to U size, our size is going to
be U size and we're going to parse to U size.
Our curd dye is going to be U size and that's all of our things.
So that's kind of what I should have done last time, but if I'm quite honest, I forgot
U size existed.
So that's on me.
The next thing that we're going to do is actually we're going to change all of these to
I sizes because I want us to be able to handle negative values.
And you might say, why do you want to handle negative values now when you didn't want
to before because now that we're kind of getting into the dice rolling thing, I think
it's a good idea to be able to in the future, we're going to be able to roll negative amounts
of dye rolls or be able to negatively add bonuses and I want it all to kind of be consistent.
So I'm going to do that, going to make everything into an I size.
So for right now, it's not really going to matter because everything is sort of just
adding up, but that's how I'm going to start.
Next thing that we want to do, which might have been a good thing to do, start, but we're
going to be thinking about how we're going to actually pop our function out of this.
Now what we could do is just use the same loop structure that we have for and just preserve
it in a function, but I'm actually going to use a couple of new rust techniques.
I'm going to introduce a for loop, I'm going to introduce an underscore variable.
I'm going to introduce the match statement and I think that's it for right now.
So right above our FN main statement, we could do it below, but let's do it below.
So at the end of your five, at the end of your file, I give you yourself a couple of
lines.
Let's type in FN, Foxtrot, November, space, ROL, Romeo, Oscar, Lima, Lima, and then
an open parentheses.
And this is our function declaration.
We're defining a function called role.
Now we need to give it some arguments.
The way that arguments work in rust is they put in the argument name, that'll be the
variable name that you use in the function, a colon, and then a type declaration for what
that argument will be as the type.
So we're going to have two arguments in this, in this function.
We're going to have num, dice, colon, space, i size, comma, space, num, size, colon, space,
i size, those parentheses.
So as I mentioned last time, variable names, which these arguments are variables, are generally
done in snake case.
So that's num, November, uniform, mic, underscore, dice, delta, india, charlie, echo, and num
sides, November, uniform, mic, underscore, sides, ceria, india, delta, echo, ceria.
And then after our close parentheses, we're going to do a space.
And now we're going to need to give a return type, because we want this to return what was
our sum variable before.
So we're going to do a minus sign and a greater than sign.
So you get a little arrow looking thing with the dash and then triangle bracket, looks
like a right arrow kind of.
And then we're going to do another space and we're going to do i size.
So india, ceria, india, zulu, echo, and that's going to be the return type.
So it's saying you take this function, call the role, it's got two arguments, num dice,
which is an i size and num sides, which is an i size.
And it's going to return something of the type i size.
So then we're going to do a space and an open curly break it and a new line.
That's how I like to do it anyway.
Then I'm going to do a tab.
And so now we're inside of our function.
And we're basically going to re-implement the things that we did before.
So the thing that we need to do first is we need to define our random number generator.
So we're going to do let space mut for mutable, space rng, space equals space thread.
Under score, rng, open parentheses, close parentheses, semicolon.
So this is the same line that we have at the top of our main function.
Well, it's the second line of our main function.
But you know, you don't mean it's close to the top of our main function.
And this is going to set up our random number generator, kind of give default entropy and all that jazz.
Then we're going to go to a new line.
And we're going to get our sum variable in here.
We're going to let mut space sum colon space i size equals zero semicolon.
And that's going to define our sum variable.
I just realized I'm pretty.
I'm pretty sure that the type.
I'm not going to say that totally out loud.
I'm just going to leave that as a thought for now.
I'll look it up later.
We've already gone this far.
Now to port.
So now we're in our role function.
I'm going to give ourselves another new line.
And so we have our sum.
So we have our number of dice and they have a number of sides.
And so now we need to roll these dice.
And there's many different ways that we can do this.
However, I'm going to use a statement called a match statement because I think it's cool.
It reminds me a lot of the case statement in bash, which is nice.
And it's just a good thing to learn because you will use it a lot in rust.
So I'm going to do match MATCH space.
And then num underscore dice.
That's the variable you have to port and then a space.
And then an open bracket, open curly brace and give ourselves some new lines.
So what this statement does is it takes the variable that you give to the match statement.
And it tries to match it to various cases.
So the first case we want it to look at is when the number of dice is positive is greater than zero.
So in on the next line, we're going to do num dice.
Space if space num dice is greater than zero.
And that basically says, so this will match num dice if num dice is greater than zero.
So then we're going to do a space.
Then we're going to do an equal sign and a greater than sign to give us another kind of like arrow looking thing.
It's slightly different than the type declaration for return values.
It can be confusing, but it's just something you have to get used to.
So we're going to do a space.
And this is where we're going to give what happens at this point.
And it can be a single function.
It can be a assignment for a variable, which we are going to do in a second.
Or it can be an entire block of code.
And that's what we're going to do now.
So we're going to do an open curly brace and a new line.
And now we're going to do inside this code block, which is just this function that's only going to run
when num dice is greater than zero.
I could have done this in an if else if statement.
But I didn't want to because that's boring.
It's functionally equivalent.
It's actually exactly the same, really.
But I think this looks better and feel free to fight me in the comments.
So what we're going to do is inside of this code block is going to be our for loop.
Or we've looped you the number of dice.
And this is going to introduce an interesting thing in rust, which is you can normally the compiler
will yell at you if you don't use a variable.
Because it's like, hey, you have all this memory.
It's just sitting there.
It's not doing anything.
You should probably do something with it.
But if you are just making a variable for an iterator or something like that that you don't really use,
then it's kind of stupid for it to yell at you for that.
So what you can do is when you're writing your code, if you put an underscore at the beginning of the variable name,
then rust will know, oh, that's just some random thing that's not actually going to be used.
I'll just leave it alone and I'm not going to worry about that.
So in this, what we're going to do is a for loop and the way that the for loop is structured.
And then I'll get into how it works is the word for FOR Fox trot Oscar Romeo space.
And then we're going to give it a iterator variable, which in this case is going to be underscore delta India echo.
And then a space and then the word in Indian of Ember and then a space.
And then we're going to do the number one and then two periods, then the equal sign and then numb dice are variable.
And so this might look very familiar to you when we did the Jen range thing and all that.
But what this is basically saying is for whatever our iterator is in the range from one to the number of dice inclusive.
So if we had a non useless iterator variable, we could use it in the for loop technically, we could still do that.
But it wouldn't be recommended in the for loop. So at the first iteration die would be equal to one that will be equal to that would be three all the way up to and including the number of dice.
So in this case, because we put that equal sign in there, it's going to include the end point.
And that's what we want. So then we're going to do a space and then we're going to do an open curly brace and then new line.
And then inside this for loop, what we're going to do is we're going to have, we're not going to worry about a current die or any of that stuff.
We're just going to directly add to our some variables. So we're going to do some and I'll show you how we're going to do that because it's kind of cool.
We're going to some space plus equals, which is a thing that's in I believe it's C plus plus I know it's in Python, but it's a way of assigning a variable while adding to it.
So like if you did some plus equals one, it would redefine some as the value of some plus one.
Here in the last episode, if we did some plus equals curdye, then that would do the same thing as our sum equals sum plus curdye, but we don't have a curdye.
So they might be asking, how the hell are we going to get our randomness in here? We don't have a current die.
The answer is another match statement because we can put a match statement here in the assignment, which is really cool to me.
So after that equals sign, the plus equals, we're going to do a space and then match and then another space and then numb underscore sides.
And then a space and then an open curly brace and then some new lines.
And then we're going to get inside this code block and our first case is going to be numb sides.
If numb sides is greater than zero, and we're going to do the equals sign greater than sign, and then a space and then our NG period, G, E, N, Underskore range, GenRange, and open parentheses, one, double dot equals numb sides.
And then a comma at the end of all of that because there's a comma separating each one of these match statements, which will come back to when we break out of all of this nonsense.
This is going to look quite complicated, but just follow around. I'll try to walk you through it and I'll re walk you through it at the end.
Hopefully, if I don't forget, okay, then we're going to go to the next line. Notice we didn't need to use curly braces or anything around the RNG GenRange because it's just that one function declaration.
So on the next line, we're going to do numb sides. If numb sides is less than zero, and then we're going to do our equals greater than and then a space and an RNG dot GenRange.
And so this is something that we're going to use later in the for loop when we do the negative numb dice as well. But in this case, what we're going to do is we're going to our first part of our range is going to be our numb sides because it's negative in this case.
And then we're going to do the double dot and then an equal sign and then negative one. So this is going to take us from our negative numb sides all the way up to negative one. And that'll be our random number range, which means that if we have a negative number of sides, then we'll end up with a negative number, a negative sign in front of whatever the die roll is.
So if we rolled one minus or one D minus six, then that I'll give us a number from minus one to minus six, which can be useful. I mean, it's not always useful, but there are certain circumstances where it'll be useful to do this.
And so I want to be able to make those circumstances possible. So then we're going to do the next line after the comma after the close parentheses, if I didn't say that. And then we're going to have numb sides space if numb sides is double equal sign space zero.
So if that's precisely equal to zero, this is the same thing that we used in the if statement last time to test if the loop numb was equal to the dice. Now we're going to do space equal sign greater than sign for that arrow and then space. And then this is an interesting thing that you can do in in rust.
If you want to make absolutely sure that your compiler knows what type you're giving to just some random number, you can actually just put it after the number. So if we do zero, I size.
So that's zero, no space, no space between this zero India Sierra India Zulu echo all as one like word type of thing. Then if you use a syntax highlighter, it'll highlight it because that is a zero of type I size.
And it's a specifically of that type. So there's no ambiguity there. And then we're going to do a comma after that.
So you might say, okay, that's that's it. That's all we need for this batch statement. We're all done. We can close parentheses it or close curly bracket it and just be done.
But rust compiler will yell at you because you need one more thing in all match statements and that's anything else. Now I hear you crying in mathematics.
The well ordering axiom states that a number can only be greater than equal to or less than any other number. Those are the only three possibilities.
But rust does not know these are mellow frankle axioms. So, you know, we kind of have to just humor it here. So the way we do that is we do an underscore and that just means if anything else happens.
And for right now, if anything else happens, if it manages to break math, then we're going to a space we're going to do an equal sign greater than sign another space.
And we're just going to return a zero of tied by size because like that's not going to happen. And we're not going to worry about it. And then we're going to do a comma and a new line.
And then we're going to closing curly bracket the num sides match statement. And we're going to put a semicolon after it. That's important.
Because this is in an assignment, we need that semicolon because it's not a full code block. It's a code block inside of another statement.
All right. So then on the next line, we're going to do a curly a closing curly bracket for our for loop. And then on the next line, we're going to do a closing curly bracket for our if the number of
or if num dice is greater than zero statement. Now we're going to do a comma because now we're going on to the next part of the num dice match statement.
And then we're going to go on to a new line. And this is where we're going to say for num dice.
If num dice is less than zero. So now if we have negative value for the number of dice, then we're going to do our equals greater than sign and then an open curly bracket and then a new line.
And then if I was using strict best practices here, or rather, if I was using best practices from 1965, which is what my dad taught me.
A rule of thumb that he gave me is that if you ever write code twice, it should be a function. And if your code goes over a page, it should be a new file.
It's kind of a good rule of thumb. I wouldn't take it too seriously, but it's like a good thing to keep in mind. And if I were doing that, maybe I would want this to be a function. However, there actually are some differences. So that would actually be more complicated. So I'm just going to write it again.
So I'm going to do another for loop. So for underscore die.
And now we're going to do num dice double dot minus one or equals minus one because now we're in the negative dice dimension.
Then we're going to do space and open curly breaks and then on a new line, we're going to do some.
And now instead of plus equals, we're going to do minus equals and then a space and then our match statement and then num sides.
And then an open curly brace and now we're just going to copy basically everything that happened before. So on the next line, we're going to have num sides if num sides greater than zero.
And then our equals greater than RNG dot Gen range, one double dot or open parentheses, one double dot equals num sides, close parentheses, comma, and then the next line num sides if num sides less than zero equals greater than sign RNG dot Gen range parentheses num.
Num sides double dot negative or equals negative one close parentheses, comma, new line num sides, if num sides is equal to zero, double equal space equals greater than zero.
I saw is comma and then our underscore statement of anything else breaks math or just return to zero by size, probably should you do something more dramatic, but you know, it doesn't have to.
So then next line closing curly brace semicolon for that some minus equal statement and then on the next line of closing curly bracket for our four statement.
So now that we finished off our two statements for if it's less than or equal to zero, the number of dice. Now we're going to go down to the next line, close the less than zero num die statement with the curly brace.
And we're going to give it a comma, we're going to go to the next line. And now it's going to be our num dice if num dice is double equal to zero and space and then our equals greater than sign and we don't actually need a block for this one, because if it's equal to zero, we're just going to return a zero i size, because if there's no number of dice.
Then then there's nothing to do with some we I could have it just return some. Yeah, no, let's let's stay consistent and have a return some here.
Then we'll do a comma after return some next line.
Everyone should know it by now. We're going to need to have our everything else underscore statement, because math doesn't exist in this universe, I guess, then space and then it equals greater than sign and another space and we're just going to return some if we break map and then a comma.
And then on the next line, we're going to close our match statement with a curly brace and then go to next couple lines and then we're going to return some at the end.
All right, and then a semicolon. So this after we go to the next line and close curly brace the function.
This is our function in its entirety.
So basically if I run through the way that this function operates, you're going to put into it a number of dice in some integer 32 bit or 64 bit probably 64 bit, but some integer and some number of sides.
The first thing on the first line of this program is going to do is initialize the random number channel with some entropy stuff.
Next thing it's going to do is it's going to allocate that some variable of type i size and it's going to initialize it to zero.
So we have that variable ready to go ready to use and it's mutable, which is important.
So next we're going to do is we're going to take that num dice argument that we were given and we're going to look at what it is.
It's going to check if it's greater than zero. It's going to check if it's less than zero. It's going to stack check if it's equal to zero.
And if it's none of those things, it's just going to return some which at this point is zero.
So if it's greater than zero though, it's going to go into that for loop. It's going to go into a for loop for each time for like from each number from one to the number of dice we gave it.
It's going to add a random number based on the number of sides we gave it.
In this case, it's going to add if that number of sides we gave it as positive, it's going to add that positive random number from one to that number of sides.
If it's number of sides we gave it as negative, it's going to add from the number of sides we gave it to negative one.
And if we gave it a zero number of sides, it's going to add zero to that sum.
And then if if the number of sides we gave it is some kind of eldritch abomination of mathematics, it's going to ignore that eldritch abomination.
It's not going to call to get a fetal smell or anything. It's just going to calmly return zero. That's what it's going to do.
And the next after it iterates through all of that, however many times, it's going to pop out of the match statement and return that sum with all of that juicy total of dice given to it.
But if instead the number of dice we gave it were negative, it's going to iterate through for those dies from the number of dice we gave it to negative one.
So that same magnitude of range.
And then it's going to subtract from our sum a random number depending on the number of sides we gave it.
We gave it a positive number of sides. It's going to subtract a positive random number from one to the number of sides.
If we give it a negative number of sides, it's going to subtract a negative number from the number of sides we gave it to negative one.
And an important note here is that if both of them are negative, it's going to actually end up with a positive result because it's going to subtract a negative which is going to be a positive.
It's going to add instead of subtracting which is kind of cool and might be useful probably not probably really not, but you know it won't break anything and it's an interesting sort of mathematical easter egg if you will.
If the number of sides we give it a zero, it's just going to add nothing to the will subtract nothing technically or add negative zero depending on how you want to look at it.
And if it breaks math, it won't call the ghost of Paul air-dosh, it's just going to calmly return zero.
And then after it iterates through that loop, it will return the sum because it will break out of that match statement.
If instead the number of dice we give it a zero, if we tell it to give us like zero d6, it's just going to return the sum which at this point is zero.
And if it breaks math in some other way, if the number of dice is that eldritch numerical abomination, then it's going to just calmly return some which at this point is zero.
And that's our whole function, that's what our function does.
So now if we go up into our main program, our main function here, we can remove this RNG declaration, this RNG mutable RNG variable declaration, and we can remove this mutable sum declaration.
We will keep the dice and the sides declaration as well as the args declaration because those will be important.
We're going to remove all of this loop, the loop num, the print for the dice, and the new line print the backslash end.
We're going to remove all of those lines. So the next line we're going to have is just that total line.
And instead of having the total line return the variable sum, since as you can probably see some does not exist in this scope, we're going to remove that the SUM out of that.
Instead, we're going to have it return roll, Romeo, Oscar, Lima, Lima, open parentheses, and then dice, comma, space, side is.
So that's the two variables that are holding our arguments from the command line.
So dice and sides accidentally put just singular side and then a close parentheses for that roll declaration.
And so what that'll be is that that'll take the two arguments we gave it, put it through our function, and then pop it back on that total line.
So if I save this file, and then I go into our rest 101 directory, the project folder, so that's the place that contains our source folder, our cargo.tumble and everything else.
And I run cargo space run space double hyphen space one space six. So if you remember from the last episode, it's going to compile our program.
It's going to run our program and then that double hyphen is bash interpretation for that's all we're doing with this function. And then we're going to just add in these extra arguments to the next things.
This is going to give the one in the six as arguments to our our program that we're writing.
So this should roll one D six one six sided dot if I hit enter.
It's going to fetch down the crates because this is a new computer that I haven't done this before on it's fetching the random number grade from the interwebs.
And it is still fetching because I am I did all of this on my laptop, which means it isn't pre downloaded, which means it takes a while because compiling takes a while and downloading also takes a while.
So I'm just filling dead air and how until this thing finishes it'll go faster every other time because it'll already be on my computer.
And there it goes. So it's now downloaded all of the random dependencies as well as the random thing that's compiling all of it.
And will you look at that I don't know how to spell I got an error cannot find value for numb sizes in this scope at sizes Sierra India Sierra Echo Sierra because I don't know how to spell sides apparently Sierra India Delta Echo Sierra.
So that's just me being you know spelling monstrosity so like clear that and I run the same thing again cargo run double hyphen space one space six.
Then I get a one as the output wow which look at that one I think we can totally tell that this is working so I'm going to do the same thing cargo space run space double hyphen space one and this time I'm going to do space 100.
And we got a 67 at the end total colon 67 I'm going to run it again we get 89 going to run it again we get a 69 nice.
Now I'm going to do 1d2 to make sure that we get both the upper and lower bound got 2 got a 2 got a 1 got a 2.
I'm going to give it a zero as one of the options I'm going to do 1 and a zero I'm going to give a zero.
I'm going to do a zero and one and I get a zero I'm going to do a negative one and a two and I get a negative one and if I do it again I get a negative two.
I'm going to do a negative one space negative two and I get a positive two as the answer so it all looks like it's running smoothly running very well.
So there's a couple of things that I want to do more in this video but I can feel my voice starting to go I have not been drinking enough water.
And I don't have very much water in front of me so I'm going to call this episode here I'm going to continue next time with some some more fine tuning of this function I wanted to return a vector of di rolls rather than the total.
That way we can do the total separately and maintain all of our di rolls in case we want to do something with that I want to go into more of error handling because I haven't touched on that very much yet.
But for now I think that this is enough new information and interesting information to sort of see she the rust miss for now because I think that rust is super interesting and super cool programming language.
And I think that match statement the way it handles ranges of being able to embed a match statement in a function declaration or a function assignment is super cool concept of eye size is a super cool thing that I forgot completely existed last time.
But yeah that's about it feel free to contact me on master done I'm black kernel at next death on social email me at easy leave with sub m dot me yeah just contacts me with all of the ways that I have in the description.
Hopefully I actually write show notes for this episode because one I am tired into I apparently don't know how to write HTML but anyway that's it for now and I'll see you next time.
You have been listening to Hacker Public Radio at Hacker Public Radio does work today show was contributed by a HBR listener like yourself if you ever thought of recording a cast and click on our contribute link to find out how easy it really is.
Hosting for HBR has been kindly provided by an honest host.com, the internet archive and our sync.net.
On this advice status today show is released on their creative comments attribution 4.0 international license.