Before I continue, let's make sure we're talking about the same things. This is a getter:
This is not a getter:
return Rect(0, 0, self.width, self.height)
What's the difference? One is useful, the other is not.
In older OOP paradigms used by C++, Java, PHP, etc., there's this crazy notion that class variables shouldn't be exposed to the outside. But people are also learning OOP coming from an imperative style, or being taught by someone who came from an imperative style, and program designs involve lots of mutation and little local scope. They trick themselves into believing that getter and setter methods allow them to keep their variables private, and somehow this doesn't violate encapsulation.
But it does violate encapsulation. If you have a private variable named x, and you are getting at it through getX() or setX(), you're violating encapsulation just as if you made x public and accessed it directly. If you later change the implementation so that x changes, do you really think you're going to get away with not having to change outside code, especially in a statically typed language? Maybe x was an int and now x is internally a float. Are you going to leave getX() returning an int, and just typecast it on the way out? That's horrible, horrible, horrible.
I'd say the majority of OOP languages and classes encourage this poor behaviour. Smalltalk at least provides a sensible way to provide access (I believe C# might do something similar), letting you minimally define a setter/getter function for a private member:
age: newAge age := newAge
But it's nevertheless all wrong. If you find that your design requires you to have lots of outside access to a class's internal variables (either through direct access (the proper way) or through getter/setter methods), then your design is wrong. You just want a container to keep your namespace sane, in other words you just need a simple struct.
The principle of OOP is to have objects be mostly opaque. They should do all the work themselves and the user should just have to call meaningful function names to perform work.
Of course, let's not be retarded. Violating encapsulation isn't necessarily evil. Python is a true multi-paradigm language and recognizes that the whole public/protected/private nonsense is nonsense. In Python, you don't have the ability to make something private*. This is because if you need to access something, just access it and don't waste time writing a useless get or set method. If you need to access something like that, it's not necessarily bad, but you have to realize you're not really doing proper OOP and need stop trying to use OOP ways of handling the problem. You just want a struct, possibly with some related functions grouped together, and Python will get out of your way to let you do that. Doing proper OOP is perfectly fine, too. In your design, just don't access the members directly. You as a programmer are responsible.
Is your code largely driven from your main() function? That is, is your main() function doing a lot of the work? Then you're doing OOP wrong. Follow the principle of "draw thyself". Instead of collecting images from every object you intend to draw in the main function, then drawing them in a loop, simply pass the screen buffer to each object and have it draw itself. Even better, have something like a sprite group dedicated to erasing, updating, and drawing sprites. Inside that object you can violate the encapsulation of a sprite object to get at an image, or continue following the draw-thyself form. Do whatever makes the most sense for your design.
You gain nothing and lose readability as well as efficiency in programming time and runtime by making getter and setter methods. Just make the variable public and realize you're not doing OOP any more. Even something like get_rect() isn't highly OOP'd, but it is a valid use of a get method because it actually does some work with its member variables that the caller shouldn't have to do.
I really think functional programming should be taught first to new programmers, before imperative and before OOP. Get people used to the idea of having unviolated local state and not having mutable data and side-effects and other most-of-the-time-evils, then introduce it later as a valid option for certain problems. (Video game programming for example.) Teachers shouldn't be trying to mask structs-with-functions as proper OOP programming; too often are examples made to teach OOP that just follow this idea. "Oh, here's a Student class. We want to get/set gpa, age, name, etc., so here's a bunch of getter and setter methods for that. Isn't OOP great?" WRONG. You're not doing OOP, you're making a container for a group of related variables and you're wasting time and fooling yourself into OOP by making getter and setter methods. A real Student class made with an OOP design would do work; for example, a take_test() function. Then maybe, just maybe, the caller would need to know if the student passed or not through a student.passed flag. Even better, let it know through the return value of take_test(). Or possibly better yet, the student can write to a database or file itself, and then the caller can look there instead of inside the student and can load the take_test() function off on another thread and do other stuff while it waits for the results. (Even having multiple students taking multiple tests all at once in different threads.)
Next on my list of peeves about programmers thinking they're doing OOP when they're not: unnecessary inheritance. Yes a Cat is a Mammal which is an Animal which is a LifeForm, but that doesn't mean you need anything other than a Cat class. Anyway, I'm done.
*Yes, if you prefix a variable with two underscores in Python, it is "private". But what really happens is the interpreter just sticks the class name in front of the variable. self.__x in a Foo class from the outside would be accessed through myfoo._Foo__x.
Posted on 2010-04-28 by Jach
Rick O July 15, 2010 06:15:14 AM Arg. I meant to link it: