That's not very convincing. Why can't a "dog" be a perfectly ordinary data structure that you manipulate the usual way?
while True:
for dog in dogs:
if dog["hungry"] == True:
dog["lastfed"] = time()
dog["hungry"] = False
Okay, I hear you say, but the fact that a dog is an associative array is an implementation detail. Supposing I want to abstract that - don't I need objects then? No! Just define some functions:
while True:
for dog in dogs:
if is_hungry(dog) == True:
update_last_fed(dog)
satiate_dog(dog)
So you end up with an abstract type (dog) and a bunch of functions that operate on that abstract type. Is there any advantage to "gluing" the functions to the data? Well yes, but it's subtle. Imagine you had two types of animal:
while True:
for pet in pets:
if species_of(pet) == "dog":
if is_dog_hungry(pet) == True:
update_last_fed_dogfood(pet)
satiate_dog(pet)
elif species_of(pet) == "canary":
if is_canary_hungry(pet)
...etc etc ad nauseam
With objects, you can make this elegant with pet.satiate() etc. Note however that this problem goes away with multiple dispatch - there's no reason why the language couldn't be designed so that satiate(pet) called different functions contingent on the type of pet. We already do this for math! Adding two floats is mechanically distinct from adding two ints, but it's a rare language that makes the programmer use different functions.