Lists and Memory

Lists and memory

Are lists atomic values?

Based on what we’ve already learned, they must not be–we can modify them in place! So, what happens when we create a list–say, a list of Posn’s?

> trees = [Posn(1, 3), Posn(3, 6)]
Dictionary name value
  trees loc 1
Memory location value
  loc 1 [loc 2, loc 3]
  loc 2 Posn(x=1, y=3)
  loc 3 Posn(x=3, y=6)

Indexing into lists

What happens when we evaluate:

> print(trees[1].x)

List methods

> trees.append(Posn(5, 10))

First, we’re calling a data constructor so we add Posn(5, 10) to memory at loc 4. Then we add it to the list!

Updates inside lists

What’s the difference between:

> trees[1].y = 4
> trees[1] = Posn(1, 4)

An example: ecology simulator

Imagine we’re doing a simulation of animal behavior patterns. We have a couple of classes:

@dataclass
class Habitat:
  food: int
  # could have other fields here--location, temperature, etc.

@dataclass
class Animal:
  time_since_food: int
  food_consumption: int
  habitat: Habitat

Each habitat is going to support multiple animals, who will consume the food in that habitat via this function:

def maybe_eat(animal: Animal):
  if animal.time_since_food > 8:
    animal.habitat.food = animal.habitat.food - animal.food_consumption
    animal.time_since_food = 0
  else:
    animal.time_since_food = animal.time_since_food + 1

Let’s say we wanted to create a couple of animals sharing the same habitat, which will start with 50 food. How would we do it?

Option 1:

> animal1 = Animal(0, 10, Habitat(50))
> animal2 = Animal(0, 20, Habitat(50))

Option 2:

> animal1 = Animal(0, 10, Habitat(50))
> animal2 = Animal(0, 20, animal1.habitat)

Option 3:

> habitat = Habitat(50)
> animal1 = Animal(0, 10, habitat)
> animal2 = Animal(0, 20, habitat)

Option 4:

> food = 50
> animal1 = Animal(0, 10, Habitat(food))
> animal2 = Animal(0, 20, Habitat(food))

See the lecture capture for the details.