Earlier quoted context omitted.
None of these situations require an object to do. You can always have a function that takes in an extra ‘state’ argument. You can then do everything you said by passing in the corresponding state values.
Nothing made this as clear for me as using the Nim language, where functions defined as proc doThing(x: MyObject; value: string) can be called both with doThing(x, y) and with x.doThing(y) where x by itself is 'just' a data object, but is treated transparently by the language as having associated functions, setters, getters, etc as if it were a class (even though they can all also be directly called separately). It's…
class MyObject:
def doThing(self, value: str) -> None:
# whatever
pass
obj = MyObject()
obj.doThing("value!")
MyObject.doThing(obj, "a different value!")
The only difference is that doThing is namespaced to the MyObject class.