Arkanis A blog about random stuff, but mostly programming.

Are getters and setters object oriented?

programming, php, D, simplicity

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. 🙂

react

nice meh bad surprised confused agree disagree

Comments

Newsfeed