Writing OO in a Functional state of mind

sarah johnston
5 min readApr 21, 2016

--

I have recently been working in Elixir, and now I am revisiting my TicTacToe code through new functional-tinted lenses, but the question that arose in my mind was, how far should I take it? I can’t do away with state in a language like Java entirely as it would not be idiomatic to do away with Class and only use Java’s functional interface types. [Note, I’m not even sure this is possible!] So, what else could I take from functional paradigms?

  1. Immutability — this is the big one in functional: you cannot change state of a collection or a variable or anything, instead you have to create a new collection/variable/etc with any changes included. In OO languages though, it is essentially all about manipulating state: objects maintain data(state) and perform actions on that data(behaviour). However, what we can do to emulate immutability is to create a new instance of an object whenever it’s state must change, rather than modifying an existing instance. Another thing we can aim for are methods which have no hidden side causes/effects which are also know as ‘pure’:
  2. Pure functions — a ‘pure’ function (or in OO, a method) must satisfy two conditions: it must have no hidden side causes(inputs) or side effects(outputs), and given a set of inputs, the method will always give you the same output. This post explains about side causes/effects brilliantly. In functional this restriction is clear cut, but in OO languages there are some difficult questions which I will discuss below. But, suffice to say, we can fulfil this principal most of the time.
  3. Enumerable — Methods for traversing collections and performing actions e.g. Ruby’s Enumerable Module or Java8’s Streams. e.g. map, filter, reduce, all, etc.. Strictly speaking these don’t make a language functional, but they do help a great deal with manipulating collections of data.

1. Immutable Objects in OO

Example: In a game of TicTacToe, a class called ‘Board’ maintains the state of the collection (List/Array/etc) that maintains the moves as they are played. Obviously this state is changing all the time, but rather than change the same Board instance every time, a new Board object could be created with the new state after a move.

private List<Mark> grid;
private int dimension;
public Board(int dimension, List<Mark> initialGrid) {
this.dimension = dimension;
this.grid = deepCopy(initialGrid);
}
public Board playMark(int position, Mark mark) {
if (validPosition(position)) {
grid.set(position, mark);
}
return new Board(dimension, grid);
}

2. Pure OO Class Methods

I was discussing with some of the craftspeople recently about applying functional programming ideas to the OO languages Java and Ruby. The discussions have been interesting and it highlighted to me that this was a topic that wasn’t completely mapped out to them either. However, as always it was good to discuss and I came to a few conclusions, particularly about how to create pure methods in an OO language like Java.

In the above code sample, the method playMark has two hidden side causes because it is accessing the object variables grid and dimension, (and if it weren’t for the return statement creating a new instance of Board, there would be a hidden side effect because it is also modifying grid).

Does this mean this method is ‘impure’? Well, the formal ‘definition’ of a pure function I take from this post, and it says:

A function is called ‘pure’ if all its inputs are declared as inputs — none of them are hidden — and likewise all its outputs are declared as outputs.

So, according to this, the method above is impure because it accesses the member variable grid and dimension.

So we could do this:

private List<Mark> cells;
private int dimension;
...public Board playMark(int pos, Mark m, List<Mark> grid, int dim) {
if (validPosition(pos)) {
grid.set(pos, m);
}
return new Board(size, dim);
}

But this is a bit weird because, idiomatically, an object method can and should be able to access the data within the object’s scope so why pass it in?

Through discussions, I’ve come to the conclusion that, as it was in the first example, the method ‘playMark’ was still pure if we reason that the Class itself is like a partial function application where the member variables are ‘locked in’ to the scope of the object and therefore are known i.e. not hidden side causes.

This allows us to reason that an OO method can still be pure and will always give the same output when:

  1. the method parameters and the object data variables are known, and
  2. there are no unknown side effects within the method

Other Clashes Between Idiomatic Style in Java and Functional

In an attempt to rewrite Java object methods in a pure manner, I was confronted with the question of whether I should pass objects in as arguments to other methods, like I would pass a List or some other collection to a function in Elixir, creating a nested set of method calls, or whether I should assign the return value to an intermediate local variable, and then call the next method with that variable.

At first it seemed wrong to nest the method calls as I didn’t think it was particularly Java-like. I felt like I was breaking best practices or something. But after talking to a number of craftspeople, I’ve decided to be comfortable with it after all. After all it removes the need for the temporary variables which are essentially unnecessary.

Take for example this method startGame() in class ConsoleTTT:

private GameMaker gameMaker;
private Game game;
public void startGame() {
while (gameOngoing(newGameRequest())) {
createNewGame(gameOptions());
play();
displayResult();
}
}
public Map gameOptions() {
Map gameOptions = new HashMap<String, Integer>();
gameOptions.put("gameType", requestGameType());
gameOptions.put("boardDimension", requestBoardDimension());
return gameOptions;
}

public Game createNewGame(Map<String, Integer> gameOptions) {
game = gameMaker.initializeGame(
gameOptions.get("boardDimension"),
gameOptions.get("gameType"),
new ConsolePlayerFactory(this),
new ConsoleBoardDisplayer(this));
}
public void newGameFromOptions(int gameType, int dimension) {
game = gameMaker.initializeGame(
dimension,
gameType,
new ConsolePlayerFactory(this),
new ConsoleBoardDisplayer(this));
}
private void play() {
game.playAllAvailableMoves();
}

I rewrote it to be pure, and in this case I got rid of the object variable ‘game’, and then wrote the rest in two ways:

  1. In a procedural manner with temporary local variables:
public void startGame() {
while (gameOngoing(newGameRequest())) {
Map gameOptions = gameOptions();
game = createNewGame(gameOptions);
game = play(game);
displayResult(game);
}
}

2. With nested functions:

public void startGame() {
while (gameOngoing(newGameRequest())) {
displayResult(play(createNewGame(gameOptions())));
}
}
public Map gameOptions() {
Map gameOptions = new HashMap<String, Integer>();
gameOptions.put("gameType", requestGameType());
gameOptions.put("boardDimension", requestBoardDimension());
return gameOptions;
}

public Game createNewGame(Map<String, Integer> gameOptions) {
return gameMaker.initializeGame(
gameOptions.get("boardDimension"),
gameOptions.get("gameType"),
new ConsolePlayerFactory(this),
new ConsoleBoardDisplayer(this));
}
private Game play(Game game) {
game.playAllAvailableMoves();
return game;
}

I guess all three of these versions is acceptable, depending on whether you keep the object data variable or not and whether or not you like the nested method calls or not.

--

--