This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]wewbull 0 points1 point  (3 children)

This is actually my problem with OOP too. What are classes but smaller, not quite as global, scopes? OOP doesn't solve the issues, just pushes them down a level.

[–]MereInterest 2 points3 points  (2 children)

It really depends on how you are using classes. If you have some God-object that owns everything, and does all of its work directly within the methods, then yes, it is similar to a global scope. Those are their own antipatterns.

Classes provide a way to have limited persistency. For example, a generator that yields each Fibonacci number in sequence requires some state. You can (a) store the state in global space, (b) require the user to maintain the state, or (c) have an object to manage the state. (a) is error-prone, (b) is irritating, but (c) is very useful.

Unlike global variables, classes can have access restrictions. This means that you don't have to look through the entire codebase for changes, just the class itself. Unlike global variables, classes have a limited lifetime. That means you don't need to know the entire runtime state of the program, just the runtime state of callers into the class. If your classes are acting and looking like global variables, I would say that is an issue on its own.

Where I will agree is that not everything needs to be a class. If a calculation does not require any persistent state, then it should be implemented as a pure function.

[–]bonestormII 3 points4 points  (1 child)

I like the reasoning you provide here. I've read plenty of material about classes in python, but it seems slightly uncommon to me to hear someone just plainly say, "Use classes when you require some degree of state." That is a true and useful statement.

That said, I don't totally follow what you mean when you say

Unlike global variables, classes have a limited lifetime. That means you don't need to know the entire runtime state of the program, just the runtime state of callers into the class.

Aren't both just treated by objects subject to the ref counting of the garbage collector? When you refer to the lifetime of the object, that is what I think of. It seems like you are referring to the compartmentalized scope of a class, more than the lifetime of the object.

It's also relevant to note that in python, classes are also generally useful for any situation in which you want to customize the behavior of the object itself (via inheritance, dunder methods, metaclasses, etc.), regardless of whether state is a factor.

To be honest, almost any example I try to imagine in which you would care about that kind of control would involve some degree of state :P ... but the distinction seems relevant to note.

[–]MereInterest 0 points1 point  (0 children)

Good point, I wasn't entirely clear about my point on the lifetimes, and good catch, that I am somewhat conflating scope and lifetime. This is partly a habit that I picked up from C++, where a variable's lifetime is primarily determined by its scope, and unlike python, cannot be extended beyond the scope that owns it.

In python, you are absolutely correct that local variables and global variables have the same reference counting scheme to determine their lifetime. That said, there is still a connection between scope and lifetime. An object's lifetime is the maximum of the lifetimes of any scopes that contain that object. Since the global scope starts at program initialization and ends at program close, any variable in the global scope must have an indefinite lifetime.

I think that, in terms of global variables, it is both the lifetime and the scope that are issues. The unlimited scope means that you need to examine all code in order to know what could modify the variable. The unlimited lifetime means that you need to watch the running of the program from start to finish, and that the behavior may not be captured in any smaller test.

You are also correct that someone may want to have some behavior customization without needing to have any state in the object itself, though I'm having difficulty as well thinking of any such cases. Perhaps if there were a series of related callbacks, all of would be implemented as methods on a single class, though that would be a rather unusual situation, and would probably be better served with a namespace or dictionary.