# MIT 6.00SC | Lecture 04 | Machine Interpretation of a Program

The actual lecture starts at 9:26.

We have seen the square root program which we have written previously, just for reference here it is again.

```x = int(raw_input("Enter a Number to find the square root: "))
epsilon = 0.01
numOfGuesses = 0
low = 0
high = x
ans = (low + high)/2.0

while abs(ans**2 - x) > epsilon and ans <= x:
print "LOW: ", low, " HIGH: ", high, " ANS: ", ans
numOfGuesses += 1
if ans**2 < x:
low = ans
else:
high = ans
ans = (low + high)/2.0

print 'numOfGuesses =', numOfGuesses
print ans, 'is close to square root of', x

```

Now this calculates the square root, but if we have to calculate cube root, or any other higher order roots, we have to copy paste the same code multiple times to get the desired result.

This extra code will hamper in maintainability of the code, as a result it will become difficult to debug such code. The best thing a programmer can do is to write less code with the same functionality.

So write less code we need a new language construct called FUNCTIONS.

## Module

Before we give an introduction to functions, we should understand what functions will achieve for us. It will provide us with a mechanism for:-

• Decomposition
• Abstraction

### Decomposition

Decomposition allows us to create structure for our programs. It helps to break our program and create modules in the programs. There are two units of modules.

• Function.
• Class.

Modules are self-contained and reusable which can be used in multiple context.

### Abstraction

Abstraction follows the wording by Thomas Gray.

Ignorance is Bliss.

Basically abstraction suppresses details, it act like a black box of code, of which we should only understand the use of the code and can be ignorant of the internal implementation or details of its internals.

## Function

A function allows us to break code into reusable, coherent pieces. It allows use to extend an existing language with new primitives, and use these primitives just the way we use other language primitives like `float`, `string`.

An example of function is given below:-

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon

print withinEpsilon(2,3,1)
val = withinEpsilon(2,3,0.5)
print val
```

Lets dissect the above code. The first line of the code:-

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon
```
• `def` : means define.
• `withinEpsilon` : is the function name. The function name should be mnemonic.
• `x, y, epsilon` : formal parameters.
• followed by a function body.
```"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon
```
• `return` : special command, which returns the value to the one who have called.
• Specification: Tells what a function does, which is in the comment
```"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
```

Now we have get the `withinEpsilon` function to be invoked, which can be done in these 2 ways:-

```print withinEpsilon(2,3,1)      #Type 01
val = withinEpsilon(2,3,0.5)    #Type 02
print val
```

Since `withinEpsilon` returns a value we can use this function as a part of an expression.

Now if we modify the `withinEpsilon` code such that we remove the return statement.

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
#return abs(x - y) <= epsilon
```

So when we invoke the function like this.

```print withinEpsilon(2,3,1)      #Type 01
val = withinEpsilon(2,3,0.5)    #Type 02
print val
```

we will get the output as:-

```None
None
```

Because the function will return by default `None`, if there is no return statement in the function.

There is a big advantage of a function, as I can invoke `withinEpsilon` wherever I want and can avoid duplicate the code.

### Parameter and Arguments

Now to understand parameter of function, we should look at the below code.

```def f(x):
x = x + 1
print 'x =', x     #First Print, which prints x = 4
return x

x = 3
z = f(x)
print 'z =', z        #Second Print, since we are assigning the return value of function f()
print 'x =', x        #Thrid Print, since the original value of x = 3 and the function does not modify the original value.
```

The output of the above code is:-

```x = 4
z = 4
x = 3
```

Why we got this output, lets understand this.

The first 2 outputs are expected, because we are printing the value of `x` in function `f()` and returning the value `4` from function `f()`.

But the question is why does the 3 print gives `x = 3`, the reason being the variable `x` within the function `f()` if different that outside it, when we invoke `f(x)` the value of `x` if copied, and not the actual `x` is passed so that when we modify `x` inside `f()` it has no impact on value of `x` outside.

The confusion is because the formal parameter of `f()` as `x`, we could have used some other variable and it will still work.

Important question to understand is, What happens when we call a Function ?

1. The formal parameter, `x` in this case is bound to the value of the actual parameter, `x`.
2. Upon entry to a function, a new scope is created. A scope is a mapping from names to objects.

## Assert

Assert is a command, were the keyword `assert` is followed by a expression, if the expression evaluates to `True` it does nothing else, if it evaluates to `False` the program stops.

Consider the below code.

```def f1(x):
def g():
x = 'abc'
assert False
x = x + 1
print 'x =', x
g()
return x

x = 3
z = f1(x)
```

Now when we execute the above code we get the output as:-

```x = 4
Traceback (most recent call last):
File "assert.py", line 12, in <module>
z = f1(x)
File "assert.py", line 7, in f1
g()
File "assert.py", line 4, in g
assert False
AssertionError
```

We get a `AssertionError` because we have a `assert false` in `g()`. Now with the help with `assert` we will try to understand scope.

## Scope

As discussed in the above code, when the interpreter executes the above code line by line we get the following.

### Main Scope

Interpreter first creates a `main` scope, which start at the first line which is a `def` of we have a scope with the name `f1()` in the scope.

Then it jumps to the line `x = 3`, creates a variable `x` in the same `main` scope.

Then it executes the line `z = f1(x)`, creates a variable `z`, but to get the value of `z` we have to invoke `f1()`, so with this we have a `f1` scope.

### f1 Scope

Now the interpreter will execute the function `f1` line by line, so in the `f1` scope we create a `def g()` which creates a object of name `g`.

Then it jumps to the line `x = x + 1`, since `x` was a formal parameter it was already in the `f1` scope.

Then it executes `print 'x =', x`, which prints the value of x.

Then we invoke `g()`, which creates the `g` scope.

### g Scope

Now the interpreter is executing `g()`, which use the new `x` different from `f1` scope. And in the next line it assert, so we get the output from `g()` —> `f1()` —> `main` which is a stack.

### Stack frame

Scope are created as a Stack. So for the above code the stack will look like.

`g()`
`f1()`
`main()`

Now if the assert was not there, and `g()` executed the stack would look like.

`f1()`
`main()`

## Strings

Strings are non scalar value, i.e. values which can be decomposed. Consider the below example.

```sumDigits = 0
for c in str(1952):
sumDigits += int(c)
print sumDigits

```

Consider this line `for c in str(1952):` till now we have used `for in` on integer values, but we can use it on any value on which we can enumerate each and every values.

We can also do certain operation like Slice on string, consider the below code.

```s = "abc"
c = s[0:1]
print 'c = ', c
```

The output will be `a` because as in `range` we go till `n-1` term the same is done here, so slice creates a new string.

We can also used `find`, which will return the index of the character found.

## References

### Problem Sets

1. Problem Set 1: Paying Off Credit Card Debt (Due)
1.  Instructions (PDF)
2. Problem Set 2 (Assigned)
3. Problem Set 2 Due on Lecture 6

The actual lecture starts at 9:26.

We have seen the square root program which we have written previously, just for reference here it is again.

```x = int(raw_input("Enter a Number to find the square root: "))
epsilon = 0.01
numOfGuesses = 0
low = 0
high = x
ans = (low + high)/2.0

while abs(ans**2 - x) > epsilon and ans <= x:
print "LOW: ", low, " HIGH: ", high, " ANS: ", ans
numOfGuesses += 1
if ans**2 < x:
low = ans
else:
high = ans
ans = (low + high)/2.0

print 'numOfGuesses =', numOfGuesses
print ans, 'is close to square root of', x

```

Now this calculates the square root, but if we have to calculate cube root, or any other higher order roots, we have to copy paste the same code multiple times to get the desired result.

This extra code will hamper in maintainability of the code, as a result it will become difficult to debug such code. The best thing a programmer can do is to write less code with the same functionality.

So write less code we need a new language construct called FUNCTIONS.

## Module

Before we give an introduction to functions, we should understand what functions will achieve for us. It will provide us with a mechanism for:-

• Decomposition
• Abstraction

### Decomposition

Decomposition allows us to create structure for our programs. It helps to break our program and create modules in the programs. There are two units of modules.

• Function.
• Class.

Modules are self-contained and reusable which can be used in multiple context.

### Abstraction

Abstraction follows the wording by Thomas Gray.

Ignorance is Bliss.

Basically abstraction suppresses details, it act like a black box of code, of which we should only understand the use of the code and can be ignorant of the internal implementation or details of its internals.

## Function

A function allows us to break code into reusable, coherent pieces. It allows use to extend an existing language with new primitives, and use these primitives just the way we use other language primitives like `float`, `string`.

An example of function is given below:-

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon

print withinEpsilon(2,3,1)
val = withinEpsilon(2,3,0.5)
print val
```

Lets dissect the above code. The first line of the code:-

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon
```
• `def` : means define.
• `withinEpsilon` : is the function name. The function name should be mnemonic.
• `x, y, epsilon` : formal parameters.
• followed by a function body.
```"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
return abs(x - y) <= epsilon
```
• `return` : special command, which returns the value to the one who have called.
• Specification: Tells what a function does, which is in the comment
```"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
```

Now we have get the `withinEpsilon` function to be invoked, which can be done in these 2 ways:-

```print withinEpsilon(2,3,1)      #Type 01
val = withinEpsilon(2,3,0.5)    #Type 02
print val
```

Since `withinEpsilon` returns a value we can use this function as a part of an expression.

Now if we modify the `withinEpsilon` code such that we remove the return statement.

```def withinEpsilon(x, y, epsilon):
"""x,y,epsilon ints or floats.  epsilon > 0.0
returns True if x is within epsilon of y"""
#return abs(x - y) <= epsilon
```

So when we invoke the function like this.

```print withinEpsilon(2,3,1)      #Type 01
val = withinEpsilon(2,3,0.5)    #Type 02
print val
```

we will get the output as:-

```None
None
```

Because the function will return by default `None`, if there is no return statement in the function.

There is a big advantage of a function, as I can invoke `withinEpsilon` wherever I want and can avoid duplicate the code.

### Parameter and Arguments

Now to understand parameter of function, we should look at the below code.

```def f(x):
x = x + 1
print 'x =', x     #First Print, which prints x = 4
return x

x = 3
z = f(x)
print 'z =', z        #Second Print, since we are assigning the return value of function f()
print 'x =', x        #Thrid Print, since the original value of x = 3 and the function does not modify the original value.
```

The output of the above code is:-

```x = 4
z = 4
x = 3
```

Why we got this output, lets understand this.

The first 2 outputs are expected, because we are printing the value of `x` in function `f()` and returning the value `4` from function `f()`.

But the question is why does the 3 print gives `x = 3`, the reason being the variable `x` within the function `f()` if different that outside it, when we invoke `f(x)` the value of `x` if copied, and not the actual `x` is passed so that when we modify `x` inside `f()` it has no impact on value of `x` outside.

The confusion is because the formal parameter of `f()` as `x`, we could have used some other variable and it will still work.

Important question to understand is, What happens when we call a Function ?

1. The formal parameter, `x` in this case is bound to the value of the actual parameter, `x`.
2. Upon entry to a function, a new scope is created. A scope is a mapping from names to objects.

## Assert

Assert is a command, were the keyword `assert` is followed by a expression, if the expression evaluates to `True` it does nothing else, if it evaluates to `False` the program stops.

Consider the below code.

```def f1(x):
def g():
x = 'abc'
assert False
x = x + 1
print 'x =', x
g()
return x

x = 3
z = f1(x)
```

Now when we execute the above code we get the output as:-

```x = 4
Traceback (most recent call last):
File "assert.py", line 12, in <module>
z = f1(x)
File "assert.py", line 7, in f1
g()
File "assert.py", line 4, in g
assert False
AssertionError
```

We get a `AssertionError` because we have a `assert false` in `g()`. Now with the help with `assert` we will try to understand scope.

## Scope

As discussed in the above code, when the interpreter executes the above code line by line we get the following.

### Main Scope

Interpreter first creates a `main` scope, which start at the first line which is a `def` of we have a scope with the name `f1()` in the scope.

Then it jumps to the line `x = 3`, creates a variable `x` in the same `main` scope.

Then it executes the line `z = f1(x)`, creates a variable `z`, but to get the value of `z` we have to invoke `f1()`, so with this we have a `f1` scope.

### f1 Scope

Now the interpreter will execute the function `f1` line by line, so in the `f1` scope we create a `def g()` which creates a object of name `g`.

Then it jumps to the line `x = x + 1`, since `x` was a formal parameter it was already in the `f1` scope.

Then it executes `print 'x =', x`, which prints the value of x.

Then we invoke `g()`, which creates the `g` scope.

### g Scope

Now the interpreter is executing `g()`, which use the new `x` different from `f1` scope. And in the next line it assert, so we get the output from `g()` —> `f1()` —> `main` which is a stack.

### Stack frame

Scope are created as a Stack. So for the above code the stack will look like.

`g()`
`f1()`
`main()`

Now if the assert was not there, and `g()` executed the stack would look like.

`f1()`
`main()`

## Strings

Strings are non scalar value, i.e. values which can be decomposed. Consider the below example.

```sumDigits = 0
for c in str(1952):
sumDigits += int(c)
print sumDigits

```

Consider this line `for c in str(1952):` till now we have used `for in` on integer values, but we can use it on any value on which we can enumerate each and every values.

We can also do certain operation like Slice on string, consider the below code.

```s = "abc"
c = s[0:1]
print 'c = ', c
```

The output will be `a` because as in `range` we go till `n-1` term the same is done here, so slice creates a new string.

We can also used `find`, which will return the index of the character found.