TheJach.com

Jach's personal blog

(Largely containing a mind-dump to myselves: past, present, and future)
Current favorite quote: "Supposedly smart people are weirdly ignorant of Bayes' Rule." William B Vogt, 2010

Getters (Accessors) and Setters (Mutators) Are Evil

They are a plague upon Object Oriented Programming everywhere! They are concepts from a less civilized age.

Before I continue, let's make sure we're talking about the same things. This is a getter:

class Foo:

...
def getX(self):
return self.x


This is not a getter:

class Bar:

...
def get_rect(self):
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 ^age

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

Tags: programming, rant

Permalink: https://www.thejach.com/view/id/91

Trackback URL: https://www.thejach.com/view/2010/4/getters_accessors_and_setters_mutators_are_evil

Back to the top

Rick O July 15, 2010 06:14:16 AM I made same argument to the ColdFusion community a while back. It mostly fell on deaf ears.
Rick O July 15, 2010 06:15:14 AM Arg. I meant to link it:

http://rickosborne.org/blog/index.php/2008/10/14/ooverboard/
Jach July 15, 2010 07:36:13 AM Hi Rick, thanks for your comment. Your linked blog post was nice to read, and reminds me that I need to bolt on support for MarkDown and optional email-responses for new comments... Weekend project I suppose. (Heck, I'm even starting to dislike the green.)

It seems like there are either people that get it right away or don't. I was interested that you had to do some searching for real-world examples, though, since I find them everywhere. Some code I inherited to maintain and add features to for my job has some "Java structs" we need to pass data around, eventually to return it as XML to the browser. Inevitably the classes written by this one person no longer with the company all use private members and getter/setter functions, while others used by my employer and myself simply use public properties along with an annotation to tell the XML generator to access them there. (As well as fine-control over what the XML each property should look like, e.g. element or attribute or list...)

I suspect these things will never go away, but we can try. :) Your "no girls allowed" remark reminded me of a similar statement by Guido van Rossum about how "We're all adults here".
Back to the first comment

Comment using the form below

(Only if you want to be notified of further responses, never displayed.)

Your Comment:

LaTeX allowed in comments, use $$\$\$...\$\$$$ to wrap inline and $$[math]...[/math]$$ to wrap blocks.