@extends('template')
@section('title')
Lab 7: Part 1 - Drawing Memory Diagrams
@stop
@section('head')
@stop
@section('content')
# Lab 7: Part 1 - Drawing Memory Diagrams
In this part of the lab, instead of working on the computer, you will
practice drawing and modifying memory diagrams on a whiteboard. In each
part one of you will draw the diagram and then the other person will
modify it. Make sure to check your answers using the links below to
reveal what the diagram should look like.
Feel free to take pictures of the whiteboard at each step if you want to
retain them for your notes. Using a whiteboard is easier than using paper
because you will frequently need to erase and re-draw arrows.
## Memory Diagram Reminders
- Each variable gets a box. Small values, like numbers, booleans, or `None`,
are written in a box.
- Large values like strings or lists are written separately, with an
arrow starting in the box that points to the value.
* Each slot in a list is its own box that works the same way.
- When you see an `=` sign, follow these steps:
1. Identify what is on the right-hand side:
* If there's an expression on the right-hand side involving `+`,
`*`, or another operator or function call, the result depends
on the operation performed, and will usually be a newly-created
object.
* If the right-hand side just has a variable reference (possibly
with indexing involved), then the result will be a copy of
whatever is in the box that the right-hand expression
identifies.
2. Identify which box is being updated based on the left-hand side.
* If it's a variable, update that box.
* If it involves indexing, figure out which box of which list is
being updated.
3. Take the expression result and replace the contents of the box
being updated with that value. Do not create any new arrows at
this point unless the result you are using is an arrow (in that
case, the new arrow points to the same place as the one you're
copying).
- Besides assignment using `=`, Specific methods like `append`, `insert`,
and `pop` can change the contents of the object they apply to. `+=` and
related updating-assignments also change the value on their left-hand
side.
- **Arrows cannot point to slots within lists.** They can only point to
strings or entire lists.
## Simple variable diagrams
### 1. Basic Values
Partner A
On a whiteboard, draw a memory diagram for the state at the end of this
code:
```py
num = 10
word = 'hello'
```
Check your answer
![A memory diagram corresponding to the following memory report: um = 10; word = @1; @1: 'hello'](basicVars1.svg){.md}
Partner B
Modify your partner's diagram to update it based on the following
additional assignments:
```py
word = 10
value = num * word
```
Check your answer
![A memory diagram corresponding to the following memory report: num = 10; word = 10; value = 100](basicVars2.svg){.md}
### 2. Duplicates
Partner B
Draw the memory diagram for the the end of this code:
```py
a = 10
b = 10
c = 'hello'
d = 'hello'
```
Check your answer
![A memory diagram corresponding to the following memory report: a = 10; b = 10; c = @1; d = @2; @1: 'hello'; @2: 'hello' Note: It would also be valid to use @1 for both c and d.](duplicates1.svg){.md}
Note that it would also be valid to draw a second arrow in box 'd' that
points to the same 'hello' you drew for 'c'. Becuase strings are
**immutable**, it doesn't matter to the programmer whether they are
aliases or clones, and Python often creates aliases instead of clones
when it can.
Partner A
Modify your partner's diagram to update it based on the following
additional assignments:
```py
b = d
c = a
```
Check your answer
![A memory diagram corresponding to the following memory report: a = 10; b = @2; c = 10; d = @2; @2: 'hello'](duplicates2.svg){.md}
Note that it's also valid to draw a second arrow and 'hello' for 'b', but
that's more work than just drawing an arrow to the 'hello' you already
drew.
### 3. Swap
Partner A
Draw the memory diagram for the the end of this code:
```py
x = 'A'
y = x + 'B'
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @2; @1: 'A'; @2: 'AB'](swap1.svg){.md}
Note that it's not valid to draw any arrows between x and y or between
their values.
Partner B
Now modify that based on these lines of code *(Reminder: code executes
one line at a time, using whatever variable values have been defined up
to that point)*:
```py
x = y
y = x
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @2; y = @2; @2: 'AB'](swap2.svg){.md}
Note that when we assign 'x = y', the old value of x is thrown away,
since no other variables reference it.
Partner A
Now modify the diagram based on these addiional lines of code:
```py
x += 'C'
tmp = x
x = y
y = tmp
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @2; tmp = @1; @1: 'ABC'; @2: 'AB'](swap3.svg){.md}
Here we used a third variable to help facilitate swapping x and y. Note
that you don't have to draw the arrows crossed like this, but if you
update things one-by-one, your arrows may end up this way unless you
re-draw the strings 'ABC' and 'AB'. Putting 'ABC' below 'AB' avoids
having to cross any arrows. The final value of `x` here is `'AB'` and the
final value of `y` (and also of `tmp`) is `'ABC'`.
## Diagrams for Lists
### 4. List Basics
Partner B
Draw a memory diagram for the end of these lines of code:
```py
x = [11, 22]
y = x
z = list(x) # creates a clone
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; @1: [11, 22]; @2: [11, 22]](lists1.svg){.md}
Partner A
Now modify that diagram based on the following additional code that uses
indexing and slicing:
```py
x0 = x[0]
y1 = y[1]
zs = z[0:1]
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; @1: [11, 22]; @2: [11, 22]; x0 = 11; y1 = 22; zs = @3; @3: [11]](lists2.svg){.md}
Note that slicing creates a new list, and that indexing does NOT create
new references when the items at the indices used are numbers. (If the
thing in a slot being indexed slot is a reference, you'll get a copy of
that reference).
Partner B
Now add this variable to your diagram:
```py
all = [x, y, z]
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; @1: [11, 22]; @2: [11, 22]; x0 = 11; y1 = 22; zs = @3; all = @4; @3: [11]; @4: [@1, @1, @2]](lists3.svg){.md}
### 5. List Mutation
Partner A
Draw a memory diagram for the end of these lines of code:
```py
nums = [7, 23, 51]
alias = nums
clone = nums[:] # slice from start to end
```
Check your answer
![A memory diagram corresponding to the following memory report: nums = @1; alias = @1; clone = @2; @1: [7, 23, 51]; @2: [7, 23, 51]](mutability1.svg){.md}
Partner B
Now modify that diagram based on the following additional code:
```py
ext = clone + [96]
alias.append(121)
```
Check your answer
![A memory diagram corresponding to the following memory report: nums = @1; alias = @1; clone = @2; ext = @3; @1: [7, 23, 51, 121]; @2: [7, 23, 51]; @3: [7, 23, 51, 96]](mutability2.svg){.md}
Partner A
Next draw the diagram after these additional lines:
```py
p = nums.pop(1)
clone.insert(0, 3)
nl = len(nums)
al = len(alias)
cl = len(clone)
el = len(ext)
```
Check your answer
![A memory diagram corresponding to the following memory report: nums = @1; alias = @1; clone = @2; ext = @3; @1: [7, 51, 121]; @2: [3, 7, 23, 51]; @3: [7, 23, 51, 96]; p = 23; nl = 3; al = 3; cl = 4; el = 4](mutability3.svg){.md}
Partner B
Finally modify the diagram to account for this line *(note: part of this
line of code does NOT make sense)*:
```py
alias = alias.append(239)
```
Check your answer
![A memory diagram corresponding to the following memory report: nums = @1; alias = None; clone = @2; ext = @3; @1: [7, 23, 51, 121, 239]; @2: [7, 23, 51]; @3: [7, 23, 51, 96]](mutability4.svg){.md}
Note that `append` modifies the list you apply it to, but its result
value is `None`. You should *never* write `variable =
variable.append(...)` because this will replace the variable's value with
`None`, which isn't useful. Just write `variable.append(...)` on its own
instead, as we did in the second step for this example.
Note also that the number does in fact get appended to the list in
question, which we can still see because `alias` was an alias of `nums`.
Also note that the length of the nums list is now 4, and `alias` isn't a
list any more, but the `nl` and `al` variables don't get updated: they
hold the old length values computed previously.
### 6. List Mutation 2
Partner A
Write the memory diagram for the end of this code:
```py
x = [80, 75, 50]
y = x
z = [x, y[1]]
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; @1: [80, 75, 50]; @2: [@1, 75]](xyz1.svg){.md}
Partner B
Now modify that to reflect the state after these two lines have been run:
```py
x[0] = 100
y.append('hi')
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; @1: [100, 75, 50, @3]; @2: [@1, 75]; @3: 'hi'](xyz2.svg){.md}
Partner A
Finally show what memory looks like after these two additional lines:
```py
z.insert(1, x[1] + y[1])
removed = z[0].pop(1)
```
Check your answer
![A memory diagram corresponding to the following memory report: x = @1; y = @1; z = @2; removed = 75; @1: [100, 50, @3]; @2: [@1, 150, 75]; @3: 'hi'](xyz3.svg){.md}
### 7. Mutation in a Loop
Partner B
Draw the memory diagram for the end of this code:
```py
s = []
t = []
for i in range(3, 25, 7):
s.append(i)
```
Check your answer
![A memory diagram corresponding to the following memory report: s = @1; t = @2; i = 17; @1: [3, 10, 17, 24]; @2: []](loopy1.svg){.md}
Note that since `t` remains empty, it ends up as an empty box without any
slots in it.
Partner A
Now draw the memory diagram after these additional lines of code have
run:
```py
for i in range(3):
t.append(s[i])
```
Check your answer
![A memory diagram corresponding to the following memory report: s = @1; t = @2; i = 2; @1: [3, 10, 17, 24]; @2: [3, 10, 17]](loopy2.svg){.md}
This code copies the first three entries of `s` into `t`. Note how re-using `i`
as the loop variable changes its value. Although not shown here, `i` changes
value in every iteration of the loop.
Partner B
Next, draw the memory diagram after these additional lines of code
have run *(note: these lines of code don't make a lot of sense)*:
```py
for x in s:
x += 1
```
Check your answer
![A memory diagram corresponding to the following memory report: s = @1; t = @2; i = 2; x = 25; @1: [3, 10, 17, 24]; @2: [3, 10, 17]](loopy3.svg){.md}
Note that values in `s` are unchanged: the loop copies those values into `x`,
and then changes `x`. This code doesn't make sense because `x` gets overwritten
in every iteration, and nothing else is changed. We could have just said `x =
s[-1] + 1` to set `x` equal to one more than the last element in `s`.
Partner A
Next, draw the memory diagram after these additional lines of code have
run *(note: these lines of code make more sense than the ones above)*:
```py
for i in range(len(s)):
s[i] += 1
```
Check your answer
![A memory diagram corresponding to the following memory report: s = @1; t = @2; i = 3; x = 25; @1: [4, 11, 18, 25]; @2: [3, 10, 17]](loopy4.svg){.md}
Here we actually modify the values in `s` within the loop, adding 1 to each
value. That's because we're using indexing directly to set values within the
loop.
Note that `i` also changes since we used it as our loop variable.
Partner B
Finally, draw the memory diagram after these lines:
```py
u = []
for x in t:
u.insert(0, x)
```
Check your answer
![A memory diagram corresponding to the following memory report: s = @1; t = @2; i = 3; x = 17; u = @3; @1: [4, 11, 18, 25]; @2: [3, 10, 17]; @3: [17, 10, 3]](loopy5.svg){.md}
This code copies `t` in reverse order, since each new item it sees is farther
along in `t` but is being added to the beginning of `u`. Note that `x` also
gets overwritten.
Whew! Done with drawing memory diagrams. Now move onto the next part of the lab
where you'll get practice writing code involving memory diagrams.
@include('/labs/lab07/_toc')
@stop