I'm reading 'Clean Code' from Robert C. Martin and I can't fully understand the 'Have No Side Effects' and 'Output Arguments' sections on pages 44 to 45.
In the 'Have No Side Effects' section it is stated that changes passed to parameters of a method are considered side effects and should not be done.
In the 'Output Arguments' section, it is stated that the parameters of a method should not be mutated. A method should only change the state of its owning object if some state has to be changed.
I do understand that side effects and output arguments can lead to confusing behavior and bugs if the method which does specify this behavior is called by a client who is not fully aware of that. Also, this is problematic when working in a multi-thread environment.
But with respect that the 'Clean Code' book is written based on examples with Java, I'm confused.
Let's take a look at an example. Let's assume we have a player class:
public class Player {
private int healthPoints;
private boolean alive = true;
public Player(int healthPoints) {
if(healthPoints < 1) {
throw new IllegalArgumentException();
}
this.healthPoints = healthPoints;
}
public boolean isAlive() {
return this.alive;
}
public void fight(Player otherPlayer) {
//do some fighting which will change this instance
// but also the otherPlayer instance
}
}
If we now call the following function:
player1.fight(player2);
This will change the status of player1 and also the status of player2. This is discouraged by Robert C. Martin in most cases. But in reality, I see this pattern a lot. The most Java programs really on mutation and objects are changed outside the scope in which they have been created.
If we create a battle which changes both players, it is even worse because now the other object mutates two parameters inside its method:
battle.fight(player1, player2)
Do I miss something here? When is it ok to mutate parameters inside a method(in Java)? I asked a quite similar question some time ago(Is mutating object-parameters in a method(in Java) a bad practice?).
Battle
-objects twoPlayer
-properties and then just call.fight()
on theBattle
-object. That way, theBattle
-object would only mutate its own state, i.e. itsPlayer
s. – Nicotineboolean isStrongerThat(Player other) { boolean result = this.points > other.points; this.points++; other.points--; return result; }
. The caller, based on the return type of the method and its name, expects no side-effect from such a method, but it changes the state of the two players, which is unexpected. – Tiszaclass Sword extends Weapon
, which has nothing to do with reality. – Cordie