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. :)