Feed Sign in with OpenID OpenID

Simon Willison’s Weblog

Casting out getters and setters

Python Is Not Java by Phillip J. Eby (via Ned) is the most useful article on programming I’ve read in ages. If you have any interest at all in either language, go and read it. It’s all good, but the part that really struck a nerve for me was this:

Getters and setters are evil. Evil, evil, I say! Python objects are not Java beans. Do not write getters and setters. This is what the ’property’ built-in is for. And do not take that to mean that you should write getters and setters, and then wrap them in ’property’. That means that until you prove that you need anything more than a simple attribute access, don’t write getters and setters. They are a waste of CPU time, but more important, they are a waste of programmer time. Not just for the people writing the code and tests, but for the people who have to read and understand them as well.

Writing getters and setters in Java has always bugged me, but I’ve never quite been able to articulate the reason until now. Python’s property syntax (and Ruby’s similar attr_reader and attr_writer methods) are so much more elegant that writing those things by hand, or even auto-generating them with Eclipse, leaves a nasty taste in my mouth.

This is Casting out getters and setters by Simon Willison, posted on 3rd December 2004.

View blog reactions

Next: Google Print

Previous: Blogmarks on del.icio.us

14 comments

  1. I'm a bit confused by Python's approach: you still have to write the get and set function by hand, don't you? At least, that's what is showed in the PEP's example. Then, how can you be sure to have your get/set couple non to be called directly? And what's the performance difference, apart to be able (I suppose) to invoke c.size instead of c.get_size()?

    As far as I know, Ruby works a little differently: attr_[reader|writer|accessor] generates automatically a one or a couple of methods (C#size and C#size=) to access a field. Then, you can obviously override those if you need to do more computation.

    Giulio Piancastelli - 3rd December 2004 17:20 - #

  2. Giulio: The difference is that in Java you have to start out using setX and getX methods if you want to add code later. This results in a whole lot of get/set methods that all do the same thing: get/set a private member (hehe).
    public class X {
      private String y;
      public X() {
        y = 0;
      }
    
      public void setY(String val) { 
        y = val; 
      }
    
      public String getY() {
        return y;
      }
    }
    That's just stupid and it annoys the crap out of me every single day at work. In Python, you use a normal instance attribute when that's all you need. You can go back later and add get/set methods when you need them. So it isn't that you don't write getters/setters, it's that you don't need to add them up front.
    class X:
      def __init__(self):
        self.y = 0
    That's equivelant to the Java class above. Now, let's say I want to do something on the get or set:
    class X:
      def __init__(self):
        self._y = 0
    
      def _set_y(self, val):
        self._y = 2 ** val
      
      def _get_y(self): 
        return _y
      y = property(__get_y, __set_y)
    So, in the end, you still need get and set methods but the nice thing is that you add them when you need them instead of because you might need them later. The second Python example is backward compatible with code written to the first example. Hope this helps!

    Ryan Tomayko - 3rd December 2004 17:35 - #

  3. While it's true that getters and setters do require additional computational overhead and that writing them can be a chore, there are still two good reasons for writing them:

    1. Using getters and setters allows you to later add additional sanity checking of data before it enters your object and after it leaves. This lets you remain comfortable when writing the methods for the rest of your object that you are always working with clean data. That means that you can include less error checking code at that level and code as a whole will be easier to understand.
    2. Creating getters and setters helps to insulate the code that calls your object from future changes to the object. You can freely change many of the internals of your object without having to go back and update the calls from code that used an earlier version.

    Of course, these are trade offs. You get these benefits, as long as you are willing to write the extra code, and pay the performance penalty. But, as you know, the tedious code can be generated initially and the performance penalty is very minor.

    Bob Owen - 3rd December 2004 17:49 - #

  4. Here's how properties are done in boo, which is very similar to both python and c#:
    class MyClass:
        _y  = 0 //protected field
    
        MyProperty:
            get:
                return _y
            set:
                _y = value
    
    or you can simplify all the above with:
    class MyClass:
        [Property(MyProperty)]
        _y as int
    

    DougHolton - 3rd December 2004 17:53 - #

  5. you still have to write the get and set function by hand, don't you?

    Only if they do something besides get or set the attribute. Attributes in Python are 'public' by default. As far as encapsulation is concerned, if you need to change the implementation of the class in such a way as you alter the semantics of the attribute that is accessed externally, you can simply rename the attribute to '_foo' rather than 'foo', and provide getter/setter functions for your property at that point. Up until then, you don't need them, so don't bother writing them.

    Jim Dabell - 3rd December 2004 17:55 - #

  6. Interesting... Why Nobody Didn't Notice Such Features In Delphi Where They Were For Ages :-)

    I Wonder Also If The Next Discussion Around Blogs Will Be Around, Say, Delegation Of Interface Implementation To Properties... Does Python Have It?

    Maniac - 3rd December 2004 18:18 - #

  7. Bob, the point is that you don't need getters and setters in Python; the day you find that you need to control access to an attribute, replace it with a property. Client code won't notice the difference.

    (the major drawback with Python properties is that code using won't work in older versions. another drawback is that people are abusing them; avoiding property getters and setters doesn't mean that you cannot have methods that are called "getthing" or "setthing" for things that don't really qualify as properties)

    Fredrik - 3rd December 2004 19:16 - #

  8. I prefer Mozilla's solution with setters/getters. Not that Java's conventions or Python's syntax are bad, but JavaScript's syntax is just sexy. ;-)

    Jimmy Cerra - 4th December 2004 18:38 - #

  9. The arguments here are about the mechanics of exposing internal state - perhaps more important is whether or not you should be exposing this state in the first place? By embrasing Tell Don't Ask design (http://www.pragmaticprogrammer.com/ppllc/papers/1 998_05.html) you'll end up enforcing the encapsulation of data and behaviour within an object, and so will have no need to expose the internal state in the first place. That's not to say there isn't a place for objects which are simply getters and setters, but their use should be extremely limited in a proper OO system.

    Sam Newman - 5th December 2004 20:11 - #

  10. Sam: exposing internal state is of course a problem, but many objects have a obvious external state that clients are expected to manipulate, sometimes with specific commands (e.g. fread()) or queries (e.g. ftell()) and sometimes by apparently plain accessors.
    Example: drawing "contexts" in Postscript, Java2D etc. have current stroke and fill patterns, current colours, etc. Clients who call "setFg(Color.RED)" are telling the drawing context to draw in red until further notice, not just asking to set the "foreground" attribute to "red", even if setFg were a simple setter.

    Lorenzo Gatti - 6th December 2004 14:58 - #

  11. I agree with Bob Owen, especially with point 2 :

    For me getter & setter is the good object approach :encapsulating internal implementation. So you can change the implementation and the signature of methods is still good.

    An simple example : An object representing a point in a 2D space. You can implement it with x and y coordinates in the space. So you create the setter and getter setX/getX and getY/getY.

    But it's not the only way to implement that Object. It can be implemented by an angle from line y=0 and distance from point (0,0). So getX is a calculation from to angle and the distance and setX calculates new values for angle and distance (with current y position : not value).

    Pascal - 7th December 2004 13:14 - #

  12. Is there an echo in here? "...the point is that you don't need getters and setters in Python; the day you find that you need to control access to an attribute, replace it with a property. Client code won't notice the difference."

    In java, an exposed member set (obj.x = 1) is different client code than a setter (obj.setX = 1).

    In Python an exposed member set (obj.x = 1) is exactly the same client code as a setter (obj.x = 1).

    The whole point is that in Python, you can implement a setter when you discover that you need it. There's no worrying about figuring out what accessors you might need some day, or otherwise making it policy to create spurious accessors because your language punishes you for deciding to do so later.

    Clearer this time?

    Jeremy Dunck - 7th December 2004 17:01 - #

  13. Btw, I should probably mention that I'm well aware of Tell-Don't Ask, and it's definitely my preferred design approach, but I chose not to get into that issue in the original post mentioned here, because I wanted to focus on code-level paradigmatic differences between Java and Python, not get into general architecture that's applicable to both languages.

    Phillip J. Eby - 8th December 2004 00:28 - #

  14. eqqweasdfasfas

    qwq - 27th April 2005 08:43 - #

Comments are closed.

Previously hosted at http://simon.incutio.com/archive/2004/12/03/getters

A django site