Tip:
Highlight text to annotate it
X
The following content is provided under a Creative
Commons license.
Your support will help MIT OpenCourseware continue to
offer high-quality educational resources for free.
To make a donation, or view additional materials from
hundreds of MIT courses, visit MIT OpenCourseware,
at ocw.mit.edu.
PROFESSOR: OK, to work.
A word of warning: fasten your seat belts.
Or, another way of saying it is, I'm going to open up the
fire hose a little bit today.
Last lecture, you might have thought this was a SHASS class,
it's not like a philosophy class, and it was important to
set the stage for what we're going to talk about, but
we talked about very high level things.
The notion of recipes, the notion of computation, why
you want to do this, what you're going to learn.
Today we're going to dive into the nitty-gritty, the nuts and
bolts of the basics of computation, and in particular,
what I'm going to do today is, I'm going to talk about
operators and operands, which we did a little bit real last
time, in particular how to create expressions, I'm going
to talk about statements as the key building blocks for writing
code, and I'm going to introduce simple sets of
programs, in particular I'm going to talk about branching,
conditionals, and iteration.
So, a lot to do.
OK?
So, let me jump straight to it.
At the end of last lecture, we started introducing some of
the pieces you want to do.
And I want to remind you of our goal.
We're trying to describe processes.
We want to have things that deduce new kinds
of information.
So we want to write programs to do that.
If we're going to write programs, we need at least
two things: we need some representation for
fundamental data.
And we saw last time two examples of that.
And the second thing we're going to need, is we're going
to need a way to give instructions to the computer
to manipulate that data.
We need to give it a description of the recipe.
In terms of primitive data, what we saw were
two kinds: Right?
Numbers and strings.
A little later on in the lecture we're going to
introduce a third kind of value, but what we're going to
see throughout the term is, no matter how complex a data
structure we create, and we're going to create a variety of
data structures, fundamentally all of them have their basis,
their atomic level if you like, are going to be some
combinations of numbers, of strings, and the third type,
which are booleans, which I'm going to introduce a little
later on in this lecture.
And that kind of makes sense right?
Numbers are there to do numeric things, strings are our
fundamental way of representing textual information.
And so we're going to see how to combine those
things as we go along.
Second thing we saw was, we saw that associated with every
primitive value was a type.
And these are kind of obvious, right?
Strings are strings.
For numbers, we had some variations; we had
integers, we had floats.
We'll introduce a few more as we go along.
But those types are important, because they tell us something
about what we want to do when we want to put them together.
OK, but nonetheless, I want to stress we have both a
value, yeah, and a type.
Once we have them, we want to start making combinations
out of them.
We want to put pieces together.
And for that, we combine things in expressions.
And what we saw as expressions are formed of operands
and operators.
And the simple things we did were the sort of things you'd
expect from numerical things.
Now I want to stress one other nuance here.
Which is, and we're going to do some examples of this,
initially we just typed in expressions into the
interpreter; that is, directly into Python.
And as I suggested last time, the interpreter is actually a
program inside of the machine that is basically following the
rules we're describing here to deduce the value
and print it up.
And if we type directly into the interpreter, it essentially
does an eval and a print.
It evaluates, and it prints.
Most of the time, we're going to be doing expressions inside
of some piece of code, inside of a script, which is the
Python word for program.
In there, I want to make this distinction, this nuance: the
evaluator is still going to be taking those expressions and
using its rules to get a value, but it's not going to
print them back out.
Why?
Because typically, you're doing that to use it somewhere
else in the program.
It's going to be stored away in a variable.
It's going to be stuck in a data structure.
It's going to be used for a side effect.
So, inside of code, or inside of a script, there's no print,
unless we make it explicit.
And that's a little bit down in the weeds, it's a detail,
but one I want to stress.
You need to, if you want something to be printed out
inside your code, you need to tell the machine to do that.
OK.
So let's do some simple examples.
We've already seen somebody's.
I just want to remind you, if I wanted to, for example, type in
an expression like that, notice the syntactical form, it's an
expression, a number, followed by an operand, followed
by another expression.
And of course I get out the value I'd like there.
Yes sir.
Oh, you don't like leaning that far to the left?
OK, if you're a Republican I'll be happy to shift
this over a little bit.
Wow, John, I got a laugh for a political joke,
I'm in big trouble.
That better?
Oh damn, all right, I'll have to do it even more.
OK, here we go, here we go, you see, I'm doing it down here, I
can't see it, does that-- ah, I hear his sighs of
relief, OK, good.
There we go.
Better.
All right.
One of the other things we showed last time is that
operators are overloaded.
And this is where you heard John and I disagree.
I don't happen to like this, but he thinks it's an ok thing.
In a particular-- if we, whoa, we don't do that, we do this--
that is, give a combination of a number multiplication in a
string, this will in fact give us back a new string with that
many replicas, if you like, of the string concatenated
together.
And if you want to do other things, for example, we can
take two strings and add-- whoops, sorry-- and add them
together, we will get out, again, a concatenation
of that string.
And these will, we'll let you work through the variations,
but these are the simple expressions we can use.
Now, sometimes things get a little interesting.
All right?
What's the value of that expression?
What do you think should happen if I evaluate that expression?
What's going to happen?
STUDENT: [UNINTELLIGIBLE]
PROFESSOR JIM ERICSON: An error?
STUDENT: [UNINTELLIGIBLE]
PROFESSOR JIM ERICSON: Great.
That means, let's check it.
It certainly is.
We bribe people.
So I, ah, by the way, John's a Yankees fan, he throws like
Johnny Damon, I'm a Red Sox fan, so we'll see if
I, how about that?
And I almost hit John along the way, great.
My third right, exactly, what can I say?
All right, so we're into bribing you as we go along
here, and all right?
You'll be badly overweight by the end of the term.
Right, it's a syntactic error, because it doesn't know
how to deal with this.
But there's an important thing going on here, if I in fact
wanted to combine those into a string, I should have told the
machine to do that, and I can do that, by explicitly saying,
take that, which is a number, and convert it into a string,
and then-- bleah, I keep doing that-- then add it
to that string.
OK, so there's an important point here.
We've got what's called type conversion.
That is, if I want to combine two things together in a
particular way, I need to make sure that I give it the
kind of operand it expects.
So STR, which I just typed up there, takes in parens, some
input, and it converts it into a string, so that now I can
use that where I was expecting a string.
John.
PROFESSOR JOHN GUTTAG: You've got a static semantic
PROFESSOR JIM ERICSON: Thank you.
And I was going to come to that in a second, but thank you,
John, for pointing it out.
All right.
Why is it a static semantic error?
The syntax is OK in the sense of, it is an operand, an
operator, an operand, so syntactically it's OK.
The semantics was what caused the problem, because the
operator was expecting a particular kind of
structure there.
There's a second thing going on here that I want to highlight,
because it's really important.
Yes indeed.
OK, there we go.
The second thing I want to highlight is, that what's
going on, is that Python is doing some type checking.
It caught the error, because it checked the types of the
operands before it applied things, and it says,
I'm going to stop.
Now, you might have said, gee, why didn't it just assume that
I wanted to in fact treat these as strings, and
combine them together?
Sounds like a reasonable thing to do.
But it's a dangerous thing.
Because in doing that, Python would then have a value that it
could pass on into some other part of a computation, and if
it wasn't what I wanted, I might be a long ways downstream
in the computation before I actually hit some result
that makes no sense.
And tracing back where it came from can be really hard.
So I actually want to have type checking as much
as I can early on.
And in fact, under type checking, different languages
sometimes fall on a spectrum from weak to strong typing.
Which basically says, how much type checking do they do?
Now, you're going to hear John and I go back and forth a lot,
as I said I'm an old time-- well I'm certainly old
time, but I'm also an old time Lisp programmer.
I love Lisp, but Lisp is certainly in the category of a
very weakly typed language.
It does not check the types of its arguments at all.
Python is, I wouldn't say completely strong, but it's
much closer to the strong end of the spectrum.
It's going to do a lot of type checking for you before it
actually passes things back.
Nonetheless, I'm also going to argue that it's probably not as
strongly typed as we might like.
So, for example, there's an expression.
Now, less than is just, if you haven't used it before, it's
just the operator you'd expect, it's comparing two things and
it's going to return either true or false depending on
whether the first argument is less than the second argument.
What's going to happen here?
Again, I need a hand so I can know where to throw candy.
I've also got on my reading glasses on, I can't
see anything.
Anybody.
TAs don't count, they get their own candy.
When it, yep.
STUDENT: [INAUDIBLE]
PROFESSOR JIM ERICSON: Good question.
Sounds like a reasonable guess, right?
How in the world am I going to compare a string to a number?
So, see how good my aim is, ah, not bad.
All right.
A good quest-- sorry, a good thought, but in
fact, son of a gun.
Or as my younger son would say, fudge knuckle.
All right?
So, what in the world's going on here?
This is a place-- I don't know about you, John, I think this
is actually really not good, because right, what this is
doing is, it's allowing-- sorry, let me back up and say
it-- it's got an overload on the less-than that allows you
to compare basically the lexicographic ordering, or this
sequence of ordering of symbols, including numbers
inside of the machine.
And this, in my mind, should have been an error.
Why in the world would you want to compare that?
Just to give you an example of that, for instance, I can do
the following: all right, the number four is less than the
string three, whereas the string four, oops, is not
less than the string three.
And this is a place where it's comparing strings and
numbers in a strange way.
So why am I showing you this?
Partly to show you that it's kind of weird, but also to tell
you that one of the things you want to do is exercise what I'm
going to call some type discipline.
Meaning, when you write code, you want to get into the habit
of A, checking out operators or procedures to see what they do
under different circumstances, either check them out or read
the specifications of it, and two, when you write your own
code, you want to be disciplined about what types of
arguments or operands you apply to operators.
Because this is something that could certainly have screwed
you up if you didn't realize it did it, and you need to have
that discipline to make sure it's doing the right thing.
OK.
One of the other things you're going to see is that some of
the operators have odd meanings.
And again, I think we looked-- Yup?
STUDENT: So, the string A is less than three, is false
PROFESSOR JIM ERICSON: Yes.
I mean, I'm sorry.
The answer is, I don't know if it's ASCII.
John, do you know, are they doing ASCII
encoding inside of here?
I'm assuming so.
So, in case you didn't understand what the the
question was, basically every symbol gets translated into a
particular encoding, a string of bit, if you like, inside the
machine, there's a particular one called ASCII, which is, if
you like, an ordering of that, and that's what the machine's
actually comparing inside of here, which is why in under
ASCII encoding the numbers are going to appear after the
characters, and you get the strange kind of thing going on.
All right.
I want a couple of other things, just to quickly remind
you, and one of them is, remember, the operators do look
at the types, so division, for example nine divided by five is
one, because this is integer division, that is, it's the
largest number of integer multiples of five to go into
nine, and there would be a remainder associated with
it, which is in fact four.
And again, you've got to be careful about how
you use the operators.
Right, having done that, we can certainly get to more
complicated things, so for example, suppose I look
at that expression.
Three plus four times five.
All right.
Now.
There are two possible values here, I think.
One is 23, the other's 35.
Because this could be three plus four, times five, or it
could be three, plus four times five.
And of course, you know, when you look at code it doesn't
pause in between them.
But what I do?
I just separated, do I do the addition first or do the
multiplication first?
Anybody know what happens In this case?
Yeah, way up, oh God I'm going to have a hell of time throwing
up there, way up at the back.
STUDENT: Standard order of operations, I guess take
the multiplication first, and add the three.
I'm going to try, if I don't make it, you know, just get
somebody to pass back, whoa!
I just hit somebody in the head.
Please pass it back to that guy.
If you want candy, sit much closer down, and that way we
can film you as well as we go along.
So the point is, there is something here called operator
precedence, which is what the gentleman said.
I'm not going to say much more about it, but basically what it
says is, with all other things being equal, things like
exponentiation are done before you do multiplication or
division, which are done before you do things like
addition and subtraction.
And so, in fact, if I wanted the other version of it, in
fact, if I do this right, it's going to give me 23 because it
does the multiplication first, if I wanted the other version
of it, I need to tell it that, by using, excuse
me, parentheses.
And in general, what I would say is, when in
doubt, use parens.
OK.
Now, that just gives us expressions.
We can start having complex expressions, you can imagine we
can have things are lots of parens, and all sorts
of things in it.
Yes, question.
STUDENT: What does it mean, the operator used, when you were
If you can't read it, I guess I'm going to have to blow that
Yeah, it's a percent, so this percent sign will
give you the remainder.
OK.
Second thing I need to do, though, is I need to, when
I get those values, I want to hang on to them.
I'd like to give them a name, so I can refer to
them in other places.
And so we saw that as well, the last piece we had here is the
ability to create variables, which have their own values,
and that's done using an assignment statement.
So in particular, that is an assignment statement.
It says, take the name x and create a binding for that
name to the value of the sub-expression and in fact
to do this, to stress a point, let's do that.
It's not just a number, it's any expression.
What Python will do, is it will evaluate that expression using
the kinds of rules we talked about, and then it creates a
binding for x to that value.
And I want to stress this, we're going to come back to it
later on in the term, so the way I'd like you to think about
it for now, is that somewhere in the machine, there's a
big space that contains all possible values.
It's a slight lie, it doesn't have all possible values,
but you get the idea.
It has, if you like, intellectually, all
possible values.
And when I create a binding, I'm taking a variable name, in
this case x, stored somewhere in a table, and I'm creating
a link or a pointer from that name to that value.
This is a nuance.
It's going to make a lot more sense later on when we
introduce mutation into our language, but I want you to
Don't think of it as a specific box into which we're putting
things; think of it as a link to a value.
I could have, for example, another assignment statement,
and that creates a binding from y into that same value, and one
of the things as a conservist I can do is, I could have a
statement like, let z be bound to the value of x.
And I said it deliberately that way.
That statement says, get the value of x, which is this
link, and give z a pointer to the same place.
To the value, not to x.
OK, and we'll just plant that idea, we're going to come back
to later on, as we carry on.
OK.
So if we have variables, one of the questions we can ask
is, what's the type of the variable.
And the answer is, it inherits it from its value.
OK.
Yes.
So if somewhere in my code, I have that statement, that
assignment statement, x now is a variable whose
value is an integer.
Unfortunately, at least in my mind, in Python, these variable
bindings are dynamic, or the type, rather, is dynamic.
Meaning, it changes depending on what the current value is.
Or said a different way, if somewhere later on in the
program I do this, x now has changed its type
from INT to string.
Now why should you care?
OK, my view is, I don't like it.
Especially in the presence of operator overload.
Because I might have written some code in which I'm
expecting that particular variable to have
an integer value.
If somewhere later on in the code it shifts to string, I
might not be manipulating that and getting actual values out,
but not what I wanted, and it's going to be really hard
for me to chase it back.
So one of the things I would like to suggest is that you
develop some good style here, and in particular, don't
change types arbitrarily.
I can't spell today.
Meaning, sometimes you need to do this, but in general
there's-- at least in my view and I don't, John, would you
agree?-- you just don't want to do this.
You don't want to make those changes.
It just leads to trouble down the road.
OK.
Now, last thing about variables, and then we're going
to start pushing on this, is where can you use them?
And the answer is, you can use a variable anywhere
you can use the value.
So, any place it's legal to use the value.
OK.
Now.
This is just sort of bringing us back up to speed and adding
a few more details in.
What we really want to do now though is start
using this stuff.
So, operands.
Let us take expressions, get values out, we can store them
away in places, but ultimately we want to do something with
them, so we need to now start talking about what are the
things we can do inside of Python, or any programming
language, to manipulate them.
And for that, we're going to have statements.
Statements are basically, if you want to think about it,
legal, and I was about to use the word expression except
I've misused that elsewhere, so legal commands that
Python can interpret.
You've already seen a couple of them.
Print, assignment, certainly two obvious statements, they're
commands to do something.
Assignment is binding a name to a value, print is saying put
it back out in the screen.
Obviously if you have print as a way of putting things out, we
expect to have ways of getting input in, we're going to see an
example that in the second.
And as we go through the next few lectures, we're going to
add in more and more of these statements.
But let's look at what we could do with this, OK?
And to do this, I'm going to use some code that
I've already typed in.
So I'm hoping you can read that, and it's
also in your handout.
This is a little file I created, all right, and I'm
going to start with a sequence of these things and walk them
along, again I invite you to put comments on that handout
so that you can follow what we're going to do.
All right?
So let's look at the first part of this.
Right now, this is just a text file.
And I've highlighted in blue up there one of the pieces
I'm going to start with.
And what do I have?
I have a sequence of commands; I've got an assignment
statement, I've got another assignment statement, I've got
a print statement, I've got an input statement, which we'll
come back to in a second.
And I want to basically try and use these things to
do something with them.
Second thing I want to note is, the little hash mark
or the pound sign, that's identifying a comment.
So what's a comment?
It's words to you, or to the reader of the code, that are
telling you what's going on inside of this code.
OK?
Now, these comments, frankly, are brain-damaged, or
computationally challenged if you prefer.
Meaning, why in the world do I have to tell the reader that
I'm binding x to the value three?
I'm putting them in there to make a point.
In general, good programming style says you put in comments
that are going to be valuable in helping you as a reader
understand what's going on inside of the code.
It could be, what's the intuition behind
this piece of code.
It could be, preconditions I want to have on input.
It could be, explanations of specific things you're doing.
But you need to have those comments there.
Now, this becomes a little bit of one of those motherhood and
apple pie kinds of lectures.
You know, your mother always told you to eat brussels
sprouts because it was good for you.
Well this is a brussels sprouts comment. everybody goes yeah,
yeah, yeah, comments, of course.
Of course we're going to do comments.
And they never do.
So my challenge to you, and I know Professor Guttag can do
this, my challenge to you is, a year from now, come back and
look at code you wrote here.
Can you still understand what it was you were trying to do?
I don't know, John, if you'd agree, right?
If you can read the code a year later, even code you wrote
yourself, it's a good sign that you put good
comments in, right?
Second good piece of style here is choice of variable names.
These are lousy.
Deliberately.
I'm just using simple things like x and y and z because I
want to make it, just get through the lecture
if you like.
But in general, the choice of variable name is a great way
of commenting your code.
Use variable names that make sense.
That little problem set zero that you did.
You read in a couple of values, you probably stored them away.
My bet is, you used simple names like x and y.
A much better name would have been firstname, lastname, as
the name of the variable to tell you what you were
trying to capture there.
OK.
The other piece I want to say about variable names is, once I
have that choice of variable name, I can use it, but in fact
there are a few things that I can't use in terms
of variable names.
So, these are an important way of documenting, but there're
some things excluded.
And in particular, there are some key words that Python
is going to use that have to be excluded.
Let me highlight that.
As I said, right now that's just text file.
I'm going to save this away-- yeah, not that way, I'm going
to save this away-- with the subscript, or the suffix
rather, py to make it a Python file.
Yeah, and I know it's already there but I'm going to do
it, and I get some wonderful colors.
But these are important, OK?
So notice what I have up there now.
Comments appear in red.
I can see those.
There's a keyword, which I'm going to highlight right up
here, print, which is in, I don't know what that
color is, orange?
There's a function in purple, there's a string in green,
and in black I have the assignment statements.
That print is a keyword.
It's a command to Python to do something.
As a consequence, I can't use it as a variable name.
All right, think about it for a second.
If I wanted to use print as a variable name, how do I get the
system to decide gee, do I want print as a value for something,
or do I want print as a command?
So there's a sequence of these that are blocked out, and I--
John, I think there are what, twenty-eight?
Something like that, TAs, is that right?
Twenty-eight keywords that are blocked?
We'll find them as we go along--
OK.
Having done this now, I can simply go ahead and run this,
and in fact if I go up here to run, you'll see I've got both
an option to check the module, though in this case I'm
just going to run it.
Oh, notice what happened.
It ran through that sequence of instructions, in particular it
bound x to the value three, and then it took x times x, got the
value of x multipied by x, which of course is nine, bound
that to the value of x, and then it printed out the value,
and now it's sitting here waiting for an input.
You notice what it did, it printed out that little, right
up here I'd said enter a number and that's what it's printed
out, so I can enter a number and it prints it out.
Great.
Let's run it again.
Actually for that, I can just use, if I'm lucky, function F5,
which didn't work, so let me try it again., here we go.
We're going to run that module.
OK.
Whoa.
What happened?
I didn't.
And it still took it.
And printed it up.
Well, this is one of the places where I want to come back to
that highlighting of what do things do?
Even though my statement said enter a number, in particular,
raw input here simply takes in a set of characters and
treats it as a string.
And then prints it back out.
So if in fact I wanted to make sure this was a number, I
should have done something like either try and convert it to a
number, which of course failed here, or put in a check
to say where it is.
So it's a way of reminding you, I've got to be careful about
the types of things that I put in.
OK.
This is still boring, so let's step on the accelerator.
What I have now is the following: I can write
expressions, do combinations of things to get out values, I can
store them away, I can print them up.
But literally all I can do at this stage is write what we
would call a straight-line program, that is, a program in
which we execute in which we execute the sequence of
instructions one by one.
Simply walk down that list.
We just walked through that list.
This is boring.
In fact, you can do some nice things to prove what is the
class of functions you can compute with straight-line
programs, and what you'd see if you did that is, it's not
particularly interesting.
OK.
Let's go back and think about our recipes.
What we use as our motivation here.
Even in real recipes, you have things like, if
needed, add sugar.
That's a decision.
That's a conditional.
That's a branch.
That says, if something is true, do something.
Otherwise, do something different.
So to really add to this, we need to have
branching programs.
What I mean by that is, a branching program is something
that can change the order of instructions based
on some test.
And that test is usually a value of a variable.
OK.
And these get a whole lot more interesting.
So let's look at a little example, and this is going to,
excuse me, both allow us introduce the syntax as well as
what we want to have as the flow of control inside of here.
So let me go back up here, and I'm going to comment
out that region, and let's uncomment this region.
I want to write a little piece of code.
It's going to print out even or odd, depending on whether the
value I put in, which is x in this case, is even or odd.
Think about that.
That says, if this thing has some particular value, I want
to do one thing; otherwise, I want to do something different.
And let's look at the syntax of this.
This is the first of the conditionals that
we're going to see.
Notice the format.
I'm going to go up there.
The first statement right here, that's just an assignment
statement, I'm giving some value to x.
We could make it something different.
And then, notice the structure here.
The next three statements.
First of all, IF is a keyword. which makes sense.
It is followed, as you can see there, by some expression,
followed by a colon.
And in fact, that colon is important, so let me
stress this over here.
The colon is important It's defining the beginning of
a block of instructions.
Yes sir.
STUDENT: [UNINTELLIGIBLE]
PROFESSOR JIM ERICSON: Based on a test.
Usually the value of a variable.
OK, so let me go back to where I am.
I'm looking at that piece of code.
What that colon is saying is, I'm about to begin a sequence
of instructions that I want to treat as a block.
So it identifies a block of instructions.
It's, and in particular, the colon is the start, and the
carriage return is the end.
Now what in the world does that mean?
I'm doing a lot of words here, let me try and say this
a little bit better.
That code says the following: the IF says, I've got an
expression, I'm going to evaluate it.
If that value is true, I want to do a set of things.
And that set of things is identified by the sequence of
commands that are indented in, this one right here, following
the colon but before I get back to the same place in
terms of the indentation.
If that test is not true, I want to skip this instruction,
and there's a second keyword else, followed by a colon, and
that tells me the thing I want to do in the case
that it's false.
So in fact if I run this, ah, and save it, and
it prints out odd.
So, what happened here?
Well, let's look at the code.
Right? x is initially bound to fifteen.
I get to the IF.
The IF says, evaluate that next expression.
In that next expression, I'm actually taking advantage of
the fact that I'm doing integer multiplication
and division here.
Right, that divide is, if x is an integer and two is an
integer, what's it going to do?
If x was even, x divided by two is going to be actually
the half of x, right?
If x is odd, that integer division is going to give me
the number of multiples of two, that go into x, plus a
remainder, which I'm going to throw away.
In either case, I take that value and multiply back by two,
if it was even I get back the original number, if it was odd,
I'm not going to get back the original number, so I can
just check to see if they're the same.
OK, so a little nuance that I'm using there.
So, the first thing that IF does, bleah that IF says is,
evaluate that expression and if it's true, do the next thing,
the thing after the colon.
In this case it's not true, so it's going to skip down
and evaluate the thing printed up the odd.
STUDENT: [INAUDIBLE]
PROFESSOR JIM ERICSON: Thank you.
I was hoping somebody would ask that question.
The question was, if you didn't hear, why do I
have two equal signs?
It's like I'm doing this, right?
Anybody have a se--%uFFFD why don't I just use an equal sign?
I want to know if something's equal to something.
Yeah.
PROFESSOR JIM ERICSON: Absolutely.
The equal sign is going to bind-- Nice catch.
John, this is so much fun, throwing candy.
I've got to say, we've got to do this more often-- Right.
Let me, let me get to the point.
What does an equal sign do?
It is an assignment.
It says, take this thing on the left and use it as a name to
bind to the value on the right.
Having already chosen to use equal as an assignment, I
need something else to do comparison.
And that's why I use double equals.
Those two equal signs are saying, is this thing equal
to, in value, the thing on the other side?
OK.
Now, having done that, again I want to stress this idea and
I'm going to write it out one more time, that there's a
particular format here.
So we have if, and that is followed by, I'm going to use
angle braces here just to indicates something goes
in here, some test followed by a colon.
That is followed by a block of instructions.
And we have an ELSE, followed by a colon in some other
block of instructions.
And I want you to get used to this, that colon is important,
it identifies the start, and then the set of indented things
identify all the things at the same level, and when we reset
back to the previous level, that's when we go back
to where we were.
OK.
Now, that's a nice simple little test, let's look at a
couple of other examples to get a sense of what this will do.
OK, let me comment this out, and let's look at this
next little piece of code.
All right.
I'm binding a z to be some value, and then
I'm going to run this.
Well, let's just run it and see what it does.
Nothing.
OK, so why?
Well, let's look at it.
I'm doing a test there to say, if the string x is less than
the value of b, and x does not appear before b as strings,
then I was going to do, oh, a couple of things,
because they're at the same block level.
Given that that wasn't true, it did nothing.
Now, wait a minute, you say, where's the ELSE clause?
And the answer is, I don't need one.
All right, if this is purely a test of, if this is true do
this otherwise I don't care, I don't need the ELSE clause
in there to identify it.
All right?
Second thing I want to look at is, suppose I compare
that the one below it.
Oops, that I don't want to do.
Comment that out, and let's uncomment this.
Yeah, I've still got a binding for z and I'm giving it the
same test, but notice now I've got the two same commands but
they have different indentation.
In this case, in fact I do get a different behavior.
Why?
Because that block identifies a set of things that I'm going
to do if the test is true.
If the test was not true, notice that that last command
for print Mon is now back at the same level as the IF, so
what this says is the IF does the test, having done the test,
it decides I'm not going to do anything in the block below it,
I'm going to skip down therefore to the next
instruction at the same level as the IF, which gets me to the
second print statement.
OK.
So now we're seeing some of these variations, let's see
what else can we do here.
So let me just to try something a little more interesting, and
then we'll get to writing some simple programs.
So I'm going to comment those out, and let's go down to
this piece of code, and uncomment it.
Ooh yes, that was brilliant.
Let's try this again.
And uncomment that, and uncomment it again.
Right, so here's a little piece of code that's going to print
out the smallest value of three.
And notice what this is showing is that the IFs can be nested.
All right, it's so if I looked at it, it's going to say that
IF x is y-- sorry, IF x is less than y, THEN check to see IF x
is less than z, and if that's true, print out x
is the smallest.
And notice the structure of it, if it's not true I'm going
to go to that next ELSE, and print out that z is smallest.
If the first test wasn't true, I'm going to skip that whole
block and just go down and print out that y was smallest.
So notice the nesting, I can flow my way through how
those tests are actually going to take place.
All right, so let's run this and see what happens.
Great. y is smallest.
Is that code correct?
Is that a tentative hand back there?
Yeah.
STUDENT: Let me compare y to [INAUDIBLE]
PROFESSOR JIM ERICSON: Yeah, it's not doing
all of the comparisons.
All right, and let's just check this out, because I want to
make a point of this, let's go back and do the following.
Let's take y, change it to thirteen, let's run it, hmm.
So what did I miss here?
Two important points.
First one, when I write a piece of code, especially code that
has branches in it, when I design test cases for that
piece of code, I should try and have a specific test case for
each possible path through the code.
And by just doing that, I just spotted, there's a bug here.
And the bug was in my thinking, I did not look
for all of the tests.
So the way I can fix that, is, let me comment that out, and
keep doing that, comment that out, let's uncomment this,
notice the structure here.
I now have multiple tests.
So actually, let's just run it and then we'll talk
about what it does.
I run this, yeah, I have a syntax error, yes indeed,
because I forgot to comment that one out, all right, and
cue, we'll try it again.
Ah-ha!
And let's quickly look at the structure of this.
This now has, gee, a funny thing, it says IF x is less
than y AND x is less than z, then do something.
And then it has a strange thing called ELIF, which is simply
short for else/if in a second test.
So the way to think about this in terms of flow is, it starts
with that if and it says, check both of those things.
And that fact that both of those things is the fact
that we're using Boolean combination here.
It is to say, we can take any logical expressions, combine
them together with AND, OR, or NOT to make a complex
expression, and use the value of that expression as my test.
And that's literally what I've done there, right, I've got x
less than y, that's a test, it returns a Boolean, which by the
way is the other type, at least I would include here, it has
only two values, which are true and false, and what that code
says, if x is less than y, AND, logically, whatever I put up
there, x is less than z, then the combination is true, and
therefore I'm going to do something.
So AND is if both arguments are true it's true, OR is if either
argument it's true it's true, NOT is if the argument is not
true it's true, and then the last piece, as I said is, I can
now have a sequence of things I want to do.
So if this is true do something else, otherwise test and see if
this is true, do something else, as many as I like
followed by the end.
And ELSE, it says, here's what I want to do.
OK.
Now.
Having added this in, I have branching instructions.
I have simple branching programs.
These are still awfully simple.
And they're awfully simple because, all I can do now, is
decide whether to execute some piece of code or another.
Said a different way, in the case of the straight-line
programs, how long would it take to run a program?
Well, basically, however many instructions I have, because
I've got to do each one in order.
With simple branching, how long is it going to take
to run a piece of code?
Well at most, I'm going to execute each instruction once.
Because the IFs are saying, if it's true do this,
otherwise skip on it.
Therefore, for simple branching programs, the length of time,
the complexity the code, is what we would call constant.
That is, it's at most the length of the actual
number of instructions.
It doesn't depend on the input.
Real simple programs.
Let's take another simple example.
Suppose I want to compute the average age of
all the MIT faculty.
There's about a thousand of us.
However I do that, I know that should inherently take more
time than it takes to compute the average age of all
the EECS faculty.
There's only 125 of us.
And that should take more time than what it takes to compute
the average of John's and my ages, instructors in 600,
because there's only two of us.
All right, those pieces of code inherently involved something
that does depend on the size of the input, or on the
particular input.
And that is a preface to an idea of computational
complexity we're going to come back to.
One of the things we want to help you do is identify the
different classes of algorithms, what their costs
are, and how you can map problems into the most
efficient class to do the computation.
Now.
Think for a second about computing the average
age of the faculty.
You can already kind of see what I want to do.
I, somehow if, I want to walk through some sequence of data
structures, gathering up or doing the same thing, adding
ages in until I get a total age and then divide by
the number faculty.
How do I write a piece of code for that?
Well, let's go back up to our original starting
point of recipes.
And I'm sure you don't remember, but one of the things
I had in my recipe, is beat egg whites until stiff.
OK.
That until is an important word.
It's actually defining a test.
Let me rephrase it into garbled English that'll lead more
naturally into what I want to do.
While the egg whites are not stiff, beat them.
That is a different kind of structure.
It has a test in it, which is that while, while something
is true, do something, but I want to keep doing it.
And so for that, we need to add one last thing.
Which is iteration.
Or loops.
We're going to see variations of this, we're going to see a
variation of it called recursion, a little later on,
but for now we're just going to talk about how do
we do iterations.
And I want to show you an example of this, to lead
to both the syntax, and to the semantics.
And let me comment that out, and let's go to this one.
What does this piece of code say?
Not, what does it do, but what does it say.
Well, the first three statements are just
assignment statements.
I'm binding x, y, and iters left to some values.
And then notice the structure, I got a keyword WHILE, there's
that color identifying it, and in parentheses I have a test.
I'm expecting the value that test to be a Boolean.
Followed by a colon.
The colon's identifying a block of code.
And what this is saying is, gee.
Check to see if the variable iters left has a value
greater than zero.
If it does, then execute each of the instructions
in that block.
So I'm going to have an assignment of y, I'm going to
have an assignment of iters left, I've got a comment that I
had borrowed in order to do some debugging, and then
what do I want it to do?
I want it to go back around to the test.
Once again, say, is that test true?
If it is true, execute the sequence of instructions.
So in fact we can block this out and see what it does.
If I make a little chart here, I've got x, y, and iters left.
x starts off as I think I set it up as, here I can't even
read it, is x is three, y is zero, iters left is three.
I can hand-simulate it.
It says, is the value of iters left greater than zero?
So, execute those two instructions.
It says, take value of y and value of x, add them
together, and create that as the new value of y.
That's the assigned statement.
It says, take iters left, subtract one from it, and
bind that as the new value of iters left.
Having reached the end of the block, go back up
and check the test.
Is iters left greater than zero?
Yes it is.
So, evaluate the same sequence of instructions again. y plus x
is six, that's my new value of y, two minus one is one, that's
my new value of iters left, go back up.
Is iters left greater than zero?
Yes it is.
So once more, thank God I didn't take 47 as an example, x
plus y, subtract one from iters left, go back up to the test.
Is iters left's value greater than zero?
No, it is not.
Therefore, skip the rest of that block of code and go
to the next instruction, which is, ah, print out y.
In fact, if we test this, son of a gun.
Got a simple square procedure,.
Right, It's just squaring an integer, is what it's doing.
But notice the structure.
Now I have the ability to create a loop, that is, to
reuse the same pieces of code over and over
again as I go around.
And this adds, now, a lot of power to the kinds
of code I can write.
Notice some other things I want to highlight on this.
All right?
The first one is, that test has to involve-- shouldn't have to,
but almost always is going to involve-- the value
of some variable.
What if I don't change the value of that variable
inside of the code?
Or, another way of saying it is, what if I did this?
Comment it up.
What happens if I run this sucker?
STUDENT: [INAUDIBLE]
PROFESSOR JIM ERICSON: Yeah.
It'll go forever.
Absolutely, right?
It's going to loop into an infinite loop-- I think I can
hit this close, ah, no I can't, boy what a terrible aim--
All right, what has [UNINTELLIGIBLE PHRASE]
try again, the point I'm trying to make here-- thank God we're
at the end of this lecture, my tongue is falling apart-- the
point I'm trying to make is, that test needs to involve some
loop variable that is changing.
Otherwise the test is always going to be true, we're going
to go off here, but this would loop forever if I did that.
Second question: or maybe a better way of saying this, and
the general format you're likely to see here is, a test
involving a variable name, which must be initialized
outside of the loop, and which interior to the loop gets
changed, so that the test is going to change.
Here's the second question.
What value of inputs, what values of x will this
run correctly for?
Probably should be integers, right?
Otherwise, this is going to be doing something
strange, but all integers?
All right, suppose I do this.
It's my last example.
Yeah, how about that, right?
We knew this was trying to do squaring, so intellectually we
know we can square -4, it ought to be 16, but what
happens here?
Double fudge knuckle.
All right?
It's going to run through the loop, accumulating the answers,
but because I'm subtracting, it's just going to keep making
x more and more negative as it goes along, again it's off
into an infinite loop.
Which is a way of reminding you that I need to think as I write
the code about what are my expectations from the input,
and how might I enforce them.
In this case, I probably want to make sure I use absolute
value of x before I carry it on.
Yes ma'am.
STUDENT: [UNINTELLIGIBLE]
PROFESSOR JIM ERICSON: You're absolutely right, because I
bind iters left to, um, yeah.
Boy, two candy for you.
You caught me making an error.
Yes.
The point is, it's not going to work, and she caught both of
them, impressive, it's not going to work because iters
left is already negative, it's just going to skip the whole
loop, and I'm in trouble, so thank you for catching that.
I was going to do one more example, but I've run you
up to the end of the time.
I'll leave the example on the handout, it shows you another
version that we'll come back to next time.
The key thing to notice is, I now have the ability to
create iterations, which extends well I can do.
And we'll see you next time.