Arkanis Development

Styles

Are getters and setters object oriented?

Published

Getters and setters are very common in Java. That is if you built a class and want it to have a property you don't make that property accessible directly but only though methods. One to read the property and one to write it. This looks like that:

class Car
{
    private float speed = 0.0;

    public float getSpeed(){
        return this.speed;
    }

    public void setSpeed(float newSpeed){
        this.speed = newSpeed;
    }
}

This produces very much code, but not doing it is considered very bad style in Java. Why? Because should the need arise to change the internal structure of the class Car the property speed maybe will no longer exist or will get a different type like a 2D vector. This would break all code that relied on a property named speed to be there. Therefore using getSpeed() and setSpeed() all over the program and forbidding direct access to speed keeps the internals of your class flexible. In short this is called "encapsulation". Well, in fact using getters and setters already throws encapsulation out of the window to a great deal… but that's something for another post. Anyway, getters and setters are often taught as encapsulation.

This is a valid technique in Java and may IDEs help by generating the getters and setters automatically. However since Java is what many people understand as the concept of object orientation some also think that getters and setters are a part of that concept. Before I start to disassemble object orientation lets just say that getters and setters are needed in Java to achieve a clean encapsulation. Thats because there is no way for a class to define code that should be run when a property is read from or written to.

Now here's the suprise: other languages do provide ways to do this. In PHP there is property overloading and in D there is the property syntax for method calls.

PHP property overloading

Property overloading basically are built in methods that are called if someone tries to read or write a property that does not exist or is not accessible (e.g. is private or protected). With that it's easy to maintain encapsulation even if the internal structure changes.

For example at first we can use public to make a property accessible:

class Car
{
    public $speed = 1.0;
}

$my_car = new Car();
$my_car->speed = 2.5;
print($my_car->speed);

Now code like this usually causes a "bad feeling". We directly access data of the class and it looks like the internal workings of the class are exposed to outsiders. That might be true for Java but in PHP we can always redefine property access. Now we change the internals of our class while still providing a speed property to the outside:

class Car
{
    private $velocity_vector = array('x' => 1.0, 'y' => 0.0);

    function __get($property){
        if ($property == 'speed'){
            // The speed is the length of the velocity vector
            $vec = $this->velocity_vector;
            return sqrt($vec['x'] * $vec['x'] + $vec['y'] * $vec['y']);
        }
    }

    function __set($property, $value){
        if ($property == 'speed'){
            // If the speed is 0 we lost the direction information.
            // Therefore keep the speed near zeor in that case.
            if ($value < 1.0e-8) $value = 1.0e-8;
            // Normalize to a unit vector and then multiply with the
            // new speed: vel = (vel / length) * speed (optimized below)
            // Note: The length of the velocity vector is the old speed.
            $speed_through_length = $value / $this->speed;
            $this->velocity_vector['x'] *= $speed_through_length;
            $this->velocity_vector['y'] *= $speed_through_length;
        }
    }
}

$my_car = new Car();
$my_car->speed = 2.5;
print($my_car->speed);

The Car class now uses a vector to keep track of its velocity. Internally this is a radical change since the speed isn't a simple property anymore but has to be calculated. However from the outside there is no change visible. And all that without explicit getters and setters.

D property syntax

In the D programming language the property syntax basically redirects access to undefined properties to method calls (if matching methods exist). The example is the same as the PHP example above, therefore I didn't insert comments. First we use public properties and if the internal structure changes we redirect the property access to method calls.

First the common case where getters and setters doesn't do anything but passing though data. Direct access will do:

import std.stdio;

class Car
{
    float speed = 1.0;
}

void main(){
    auto my_car = new Car();
    my_car.speed = 2.5;
    writefln(my_car.speed);
}

And now we wreak havoc in the inside:

import std.stdio, std.math;

struct vec { float x; float y; }

class Car
{
    private vec _speed = vec(1.0, 0);

    float speed(){
        return sqrt(_speed.x * _speed.x + _speed.y * _speed.y);
    }

    void speed(float value){
        if (value < value.epsilon) value = value.epsilon;
        float speed_through_length = value / this.speed;
        _speed.x *= speed_through_length;
        _speed.y *= speed_through_length;
    }
}

void main(){
    auto my_car = new Car();
    my_car.speed = 2.5;
    writefln(my_car.speed);
}

Again the Car class now internally uses a vector. However the code of main() hasn't changed a bit. To the outside speed it's still usable as a property.

Conclusion

At least in PHP and the D programming language you simply do not need getters and setters. There are other means of ensuring encapsulation when the internal structure changes. This actually makes public properties a useful and valid tool. If something changes we're able to replace a public property with some code.

I really want people to realize that it's worth looking at the details of a language because it can spare you much coding work and bad habits. Java needs some workarounds for missing features but there is no need to transfer these workarounds to other languages disguised as "good object orientation style" or "design patterns". Other languages have better means to do it and don't need these workarounds.

Feel free to comment about that topic. I would welcome a small discussion to see how others think about it. :)

14 comments for this post

leave a new one

#2 by
Erick

Um, it's "wreak havoc", not "wreck havoc".

#3 by
BoppreH

Actionscript 3.0 does something very similar to D, but more explicit: you have to append "get" or "set" before declaring the function to state that this method can be used with assignments. Ex:

public function set speed(value:int):void;

public function get speed():int;

#4 by
Chris W.

Don't forget about Python too!

You can just use the direct access of properties to your heart's content until you need to make a change and then use the built in method "property".

class Car(object):
   def __init__(self):
      self.speed = 2.5

…becomes…

class Car(object):
   def __init__(self):
      self._speed = (1.0,0)

   def _set_speed(self,speed):
      self._speed = some_calculation(speed)

   def _get_speed(self):
      return some_other_calculation(self._speed)

   speed = property(fget=_get_speed,fset=_set_speed)

Both objects can be interacted with like this:

a_car = Car()
a_car.speed =5.6
print a_car.speed

Cheers!

#5 by
Stephan

I fixed the typo Erick, thanks. :)

The JavaScript proxies looks very promising. It's interesting they didn't made everything interceptable (e.g. identity operator, instanceof, typeof, …). Should make debugging easier. I used a similar construct in Ruby to inject internationalized objects into Rails 1.x (SimpleLocalization plugin) and debugging these proxies was… interesting.

The more explicit approach of ActionScript 3.0 looks good. Actually in D2 it is advised to add the @property attribute to methods that are meant to be called as properties. It's not yet required though.

The Python approach looks very interesting, too. Actually defining the property with two handlers… almost a bit JavaScript like. Good to know, wouldn't have expected that. :)

#6 by
Me

This is useful. Have never thought about this. So python, PHP and D dont need setters and getters.

#7 by
S2

>> #Don't forget ruby! :) ?> # ?> class Car >> attr_accessor :speed >> end; ?> c = Car.new => #<Car:0xb77bd538> >> c.speed = 10 => 10 >> c.speed => 10 >> class Car >> def speed=(s) >> @speed=s >> end >> ?> def speed >> @speed >> end >> end => nil >> c = Car.new => #<Car:0xb779d10c> >> c.speed = 10 => 10 >> c.speed => 10 >>

#8 by
Stephan

Ruby solved this problem in a very consistent way: there simply are no externally accessible properties (in Ruby instance variables). What happens is that the attr_accessor() function defines getters and setters for all passed instance variable names. So in Ruby the indirection is always present but usually hidden by the shortcuts attr_reader(), attr_writer() and attr_accessor(). :)

The reason why I didn't mention Ruby was that I never saw Ruby code that used getters and setters (methods named "get_xyz" or something like that). Everyone uses the attr_* functions. It seems Ruby programmers simply do not have this problem thanks to the strong coding conventions of Ruby.

#9 by
Valentin

I partially agree. Because a good thing about getter and setter-Methods is that they are in fact methods. This raises some awareness, since programmers know that methods might throw IllegalArgumentExceptions or something like that. A property however has a passive role in general which may lead to a more careless use of the property.

I personally find a nice way to handle getters- and setters is the .NET-Approach. In .NET they distinguisch between fields and properties. While Properties can be used like simple fields it is perfectly clear that they might contain validation code and throw exceptions. This raises awareness on the programmers side but still makes them usable in a straightforward way.

#10 by
Stephan

I'm not sure I understand your point. The syntax for properties in C# looks somewhat strange to me but I have never really programmed in .Net so I can't judge if it's consistent with the language. I don't understand where .Net adds awareness for properties because the user of an object can use it the same way as normal fields. Otherwise it would break encapsulation (or that what's left of it with getters and setters).

I can see advantages in documentation but here Python, Ruby and D offer the same way to extract that information. In PHP it's a bit more complex since there are no established coding conventions for property overloading I know of.

Regarding the awareness that exceptions are thrown I'm a bit surprised. I don't know what programmers are supposed to think while programming .Net but it sounds strange to me that someone would actually expect a specific part of the code not being able to throw an exception. Maybe I'm spoiled by Ruby in this regard, don't know. The only thing I can think of in this direction is that try/catch blocks are a bit clumsy and therefore only used when absolutely necessary. The scope guard statement [1] of the D programming language would surely help there. But exception handling is a whole different topic.

I'm pretty sure I misunderstood your point, so if you have a view minutes I would appreciate a deeper explanation.

[1]: http://digitalmars.com/d/2.0/exception-safe.html

#11 by
Nils Jonsson

Real question is whether methods that expose state are OO. Tell, don't ask, and you'll be working with objects instead of glorified structs.

#12 by
Stephan

Well said. :)

#13 by
Andreas Stiegler

Hm, but is "property overloading" something different from wrapping setters and getters into an API to hide their existence, very similar to the way .NET properties work? This would allow having an internal _Speed as vector2, reading or writing it as float via the get and set part of a property, but accessing it just like a public field, just like in your D example above. The syntax is even quite similar. Be warned, VB incoming!

Public Class Car
    Private _Speed As Vector2
    Public Property Speed As Double
        Get
            Return Math.Sqrt(_Speed.X * _Speed.X + _Speed.Y * _Speed.Y)
        End Get
        Set(ByVal value As Double)
            If value < Epsilon Then value = Epsilon
            Dim speedThroughLength = value / Speed
            _Speed.X *= speedThroughLength
            _Speed.Y *= speedThroughLength
        End Set
    End Property
End Class

and somewhere else

Dim mercedes As New Car
mercedes.Speed = 7
Console.WriteLine(mercedes.Speed)

I might be spoiled a bit from game development, but i threw the holy grail of OO out of the window a while ago and never found it again. Performance, performance, performance

#14 by
Stephan

I programmed in VisualBasic 6.0 some years ago and I vaguely remember some kind of "Property Get" or "Property Set" stuff. Nice to see it in the new .Net syntax.

> Hm, but is "property overloading" something different from wrapping setters and getters into an API to hide their existence, very similar to the way .NET properties work?

No, it's exactly that. The whole point is that you can add "property specific" code later on without changing the code that uses the property. Java doesn't allow that and therefore the get/set Method convention was established. Unfortunately this convention got the reputation of being "good object orientation practice" and therefore people used it even in languages that do not have that problem. I saw that when Extbase was demonstrated on the WebDay 2010 [1]. Because of that I decided to write a bit about it hoping that a few people think about that before the use getter and setter methods in PHP.

[1]: http://events.mi.hdm-stuttgart.de/2010-12-10-web-day-2010#extensions-mit-php-extbase-und-fluid

In retrospective I should have chosen another title for the post. "Are getters and setters object oriented?" is aimed at the people that actually believe that getter and setter methods are an integral part of object orientation. That exposure of state actually breaks encapsulation and therefore a good deal of object orientation is an even higher-level problem that would be very difficult to understand for those people.

Leave a new comment

Having thoughts on your mind about this stuff here? Want to tell me and the rest of the world your opinion? Write and post it right here. Be sure to check out the format help (focus the large text field) and give the preview button a try.

optional

Format help

Please us the following stuff to spice up your comment.

An empty line starts a new paragraph. ---- print "---- lines start/end code" ---- * List items start with a * or -

Just to keep your skill sharp and my comments clean.

or