Saturday, March 26, 2011

Objectifying Java's Life...

This is the second post in the series which started with "Scala Comes to Life".

As much as I want to jump right to the Scala version of the Java code, I must wait. The Java code needs to be "cleaned up" at least to the point where it's similarity to the Scala code can be detected. And that's going to be a bit challenging as I have little motivation to want to write even more Java code. Alas, it must be done.

So, what needs to be done and in what order? The overall objective (for now) is to refactor the Java code towards the values of OO design, performance, configuration, multi-threading, etc.. This means the design needs to incorporate default immutability to easily enable parallel processing (later).

Frame.java:
In the current version of the code, there are references to boolean[][] content everywhere. This is a problem as arrays in Java are immutable (Sidenote: I sure wish Scala had decided to implement immutable arrays...sure could have save a tonnage of time for code needing to transition from Java to Scala). And if we are going to have default immutability, we need to change that implementation. This exposes that there are actually two problems; A) we have to figure out how to move to immutability and B) an implementation detail has "escaped" encapsulation. So, it appears we have our first strong candidate for a class.

So, we will create the class Frame and it's sole goal is to generate immutability around boolean[][] content. Here is a first pass at the new class in attempt to make it immutable (contain and control access to the array):

package com.blogspot.fromjavatoscala.life.java;

public class Frame {
  private boolean[][] content;
  
  public Frame(boolean [][] content) {
    this.content = content;
  }
  
  public boolean[][] getContent() {
    return this.content;
  }
}

This is a good start as there is no mutator/setter which moves us towards the goal of immutability. However, the accessor/getter is returning the internal array which is a leak in the immutability contract. Why? Any client who called getContent() can then make changes to the array returned and those changes will occur to the original object encapsulated array at this.content.

So, we must change the accessor/getter to return a copy of the array. This is called a defensive copy. The client might not and even probably won't change the contents of the array. However, that's not sufficient if one is needing the level of guaranteed immutibility, especially in a multi-threaded environment. So, the getContent() method now looks like this:

public boolean[][] getContent() {
    return this.content.clone(); //defensive copy
  }

Looks good, right? Well, while it is better, there's still a mutability leak. Can you find it? If you look closely, you will see that content is an array of arrays. While we are now defensively copying the over-all array, we are not also copying the sub-arrays. So, any modifications made to those sub-arrays by an untoward client would leak through to our object. Annoying subtlety, huh?

So, now the code just to return a defensive array just got a bit heavier; i.e. let's add some boilerplate to the boilerplate accessor/getter:

public boolean[][] getContent() {
    boolean[][] result = new boolean[this.content.length][]; //defensive copy
    for (int i = 0, count = result.length; i < count; ++i) {
      result[i] = this.content[i].clone(); //defensive copy
    }
    return result;
  }

Now, we need to also make sure that when the object is created, it is valid. This is also known as checking the invariants in terms of Design By Contract. To do this, we need to verify that the value passed in is valid. After verifying it exists (is not null and has a length greater than 0), we need to verify that it is uniform (all of the sub-arrays have the same length). So, let's add some more boilerplate, this time to the constructor, shall we?:

public Frame(boolean [][] content) {
    if (!(content != null)) {
      throw new NullPointerException("content must not be null");
    }
    if (!(content.length > 0)) {
      throw new IllegalArgumentException("content.length must be greater than 0");
    }
    if (!(content[0] != null)) {
      throw new IllegalArgumentException("content[0] must not be null");
    }
    if (!(content[0].length > 0)) {
      throw new IllegalArgumentException("content[0].length must be greater than 0");
    }
    for (int i = 1, count = content.length; i < count; ++i) {
      if (!(content[i].length == content[0].length)) {
        throw new IllegalArgumentException
            (   "content[" + i + "].length [" + content[i].length
              + "] must be equal to content[0].length [" + content[0].length + "]"
            );
      }
    }
    this.content = content;
  }

We're done, right? Nope! There's one more mutability leak staring us right in the face. Again, can you see it? I didn't initially, either. It's subtle, but it's the final line in constructor above. We are just assigning the reference. That means the caller can still mutate the reference changing our object's state. So, just like we had to defensively copy the accessor/getter, we now have to defensively copy the passed in array. And it's even a bit more difficult than that. Do we copy and THEN check the contents? Or do we check the contents and then copy? If we do the former, we lower (but don't eliminate) our risk profile that the caller will modify it during our copy operation. If we do the latter, it's possible for the caller to modify it into an invalid state right AFTER we have run our validation checks and just BEFORE we make the copy.

Ugh! I feel some more boilerplate coming on. Are arrays really worth this much trouble to get the simple behaviors we need? Rather than clutter the constructor with all the code for a safer (but still not perfectly safe) deep copy of the array, here's a utility method:

private boolean[][] deepCopy(boolean[][] content) {
    boolean[][] result = null;
    if (content != null) {
      synchronized(content) { //do our best to make this as multi-threaded friendly as possible
        result = new boolean[content.length][];
        for (int i = 0, count = content.length; i < count; ++ i) {
          if (content[i] != null)
          {
            synchronized(content[i]) {
              result[i] = content[i].clone();
            }
          }
        }
      }
    }
    return result;
  }

And now we have to modify the constructor so that it is using the copy as opposed to the original provided by the content parameter. Here's what that looks like:

public Frame(boolean [][] content) {
    boolean[][] threadSafeCopy = deepCopy(content);
    if (!(threadSafeCopy != null)) {
      throw new NullPointerException("content must not be null");
    }
    if (!(threadSafeCopy.length > 0)) {
      throw new IllegalArgumentException("content.length must be greater than 0");
    }
    if (!(threadSafeCopy[0] != null)) {
      throw new IllegalArgumentException("content[0] must not be null");
    }
    if (!(threadSafeCopy[0].length > 0)) {
      throw new IllegalArgumentException("content[0].length must be greater than 0");
    }
    for (int i = 1, count = threadSafeCopy.length; i < count; ++i) {
      if (!(threadSafeCopy[i].length == threadSafeCopy[0].length)) {
        throw new IllegalArgumentException
            (   "content[" + i + "].length [" + threadSafeCopy[i].length
              + "] must be equal to content[0].length [" + threadSafeCopy[0].length + "]"
            );
      }
    }
    this.content = threadSafeCopy;
  }

And that completes our creating the basic immutable class for Frame. We can now safely assert that once an instance of Frame has been constructed, like an instance of String, it will remain unchanged for the duration of it's existence. Here's the final version of Frame.java:

package com.blogspot.fromjavatoscala.life.java;

public class Frame {
  private boolean[][] content;
  
  public Frame(boolean [][] content) {
    boolean[][] threadSafeCopy = deepCopy(content);
    if (!(threadSafeCopy != null)) {
      throw new NullPointerException("content must not be null");
    }
    if (!(threadSafeCopy.length > 0)) {
      throw new IllegalArgumentException("content.length must be greater than 0");
    }
    if (!(threadSafeCopy[0] != null)) {
      throw new IllegalArgumentException("content[0] must not be null");
    }
    if (!(threadSafeCopy[0].length > 0)) {
      throw new IllegalArgumentException("content[0].length must be greater than 0");
    }
    for (int i = 1, count = threadSafeCopy.length; i < count; ++i) {
      if (!(threadSafeCopy[i].length == threadSafeCopy[0].length)) {
        throw new IllegalArgumentException
            (   "content[" + i + "].length [" + threadSafeCopy[i].length
              + "] must be equal to content[0].length [" + threadSafeCopy[0].length + "]"
            );
      }
    }
    this.content = threadSafeCopy;
  }
  
  private boolean[][] deepCopy(boolean[][] content) {
    boolean[][] result = null;
    if (content != null) {
      synchronized(content) { //do our best to make this as multi-threaded friendly as possible
        result = new boolean[content.length][];
        for (int i = 0, count = content.length; i < count; ++ i) {
          if (content[i] != null)
          {
            synchronized(content[i]) {
              result[i] = content[i].clone();
            }
          }
        }
      }
    }
    return result;
  }
  
  public boolean[][] getContent() {
    boolean[][] result = new boolean[this.content.length][]; //defensive copy
    for (int i = 0, count = result.length; i < count; ++i) {
      result[i] = this.content[i].clone(); //defensive copy
    }
    return result;
  }
}

Whew! For such a simple notion conceptually, the amount of boilerplate overhead got pretty high very quickly, huh? Onward ho!

FrameFactory.java:
Next up, we need to produce instances of Frame. There are two basic events where a Frame needs to be created; A) establishing an initial state and B) deriving a state from the state of an existing frame (i.e. applying the rules). A typical way to approach this design problem is to use the Factory pattern. A factory is used to control all the instantiations of a class (or set of classes). So, we will create a class called FrameFactory. It will have several methods correlating to these two basic events. Here's the first pass (for the very observant, I will cover the unaddressed Frame.next() method shortly):

package com.blogspot.fromjavatoscala.life.java;

import java.util.Random;

public class FrameFactory {
  public static Frame first(boolean[][] content) {
    return new Frame(content);
  }
  
  public static Frame firstRandom(int width, int height) {
    return firstRandom(width, height, null);
  }
  
  public static Frame firstRandom(int width, int height, Random random) {
    return first(generateRandomContent(width, height, random));
  }
  
  public static Frame next(Frame current) {
    if (!(current != null)) {
      throw new NullPointerException("current must not be null");
    }
    return current.next();
  }
  
  private static boolean[][] generateRandomContent(int width, int height, Random random) {
    if (!(width > 0)) {
      throw new IllegalArgumentException("width must be greater than 0");
    }
    if (!(height > 0)) {
      throw new IllegalArgumentException("width must be greater than 0");
    }
    Random randomToUse = (random != null) ? random : new Random();
    boolean[][] result = new boolean[height][];
    for (int y = 0, yCount = result.length; y < yCount; ++y) {
      result[y] = new boolean[width];
      for (int x = 0, xCount = result[y].length; x < xCount; ++x) {
        result[y][x] = randomToUse.nextBoolean();
      }
    }

    return result;
  }
}


Frame.java - next():
The last touch is to update the class Frame with the next() method, copying and adapting the implementation from FrameVersion1. The full class with the new content looks like this:

package com.blogspot.fromjavatoscala.life.java;

public class Frame {
  private static final int[][] NEIGHBOR_OFFSETS = //{x, y} pairs
      new int[][] {   {-1, -1}, {0, -1}, {1, -1}
                    , {-1,  0},          {1,  0}
                    , {-1,  1}, {0,  1}, {1,  1}
                  };
  
  private boolean[][] content;
  
  public Frame(boolean [][] content) {
    boolean[][] threadSafeCopy = deepCopy(content);
    if (!(threadSafeCopy != null)) {
      throw new NullPointerException("content must not be null");
    }
    if (!(threadSafeCopy.length > 0)) {
      throw new IllegalArgumentException("content.length must be greater than 0");
    }
    if (!(threadSafeCopy[0] != null)) {
      throw new IllegalArgumentException("content[0] must not be null");
    }
    if (!(threadSafeCopy[0].length > 0)) {
      throw new IllegalArgumentException("content[0].length must be greater than 0");
    }
    for (int i = 1, count = threadSafeCopy.length; i < count; ++i) {
      if (!(threadSafeCopy[i].length == threadSafeCopy[0].length)) {
        throw new IllegalArgumentException
            (   "content[" + i + "].length [" + threadSafeCopy[i].length
              + "] must be equal to content[0].length [" + threadSafeCopy[0].length + "]"
            );
      }
    }
    this.content = threadSafeCopy;
  }
  
  private boolean[][] deepCopy(boolean[][] content) {
    boolean[][] result = null;
    if (content != null) {
      synchronized(content) { //do our best to make this as multi-threaded friendly as possible
        result = new boolean[content.length][];
        for (int i = 0, count = content.length; i < count; ++ i) {
          if (content[i] != null)
          {
            synchronized(content[i]) {
              result[i] = content[i].clone();
            }
          }
        }
      }
    }
    return result;
  }
  
  public Frame next() {
    boolean[][] result = new boolean[this.content.length][this.content[0].length];
    //iterate through rows
    for (int y = 0, yCount = this.content.length; y < yCount; ++y) {
      //iterate through columns of particular row
      for (int x = 0, xCount = this.content.length; x < xCount; ++x) {
        result[y][x] = calcState(x, y);
      }
    }
    
    return new Frame(result);
  }
  
  private boolean calcState(int x, int y) {
    boolean result = false;
    
    int neighborsAliveCount = 0;
    for (int i = 0, count = NEIGHBOR_OFFSETS.length; (i < count); ++i) {
      int[] offset = NEIGHBOR_OFFSETS[i];
      if (isAlive(x + offset[0], y + offset[1])) {
        ++neighborsAliveCount;
      }
    }
    boolean self = this.content[y][x];
    if (self && (neighborsAliveCount < 2)) {
      result = false; //live cell dies from aloneness (too few live neighbors)
    } else if (    self 
                && ((neighborsAliveCount == 2) || (neighborsAliveCount == 3))
              ) {
      result = true; //live cell lives (sufficient live neighbors)
    } else if (self && (neighborsAliveCount > 3)) {
      result = false; //live cell dies from overcrowding (too many live neighbors)
    } else if ((!self) && (neighborsAliveCount == 3)) {
      result = true;  //dead cell births (precisely enough neighbors)
    }
    
    return result;
  }
  
  private boolean isAlive(int x, int y) {
    boolean result = false;
    
    if (    (y >= 0) && (y < this.content.length)
         && (x >= 0) && (x < this.content[y].length)
       ) {
      result = this.content[y][x];
    }
    
    return result;
  }

  public boolean[][] getContent() {
    boolean[][] result = new boolean[this.content.length][]; //defensive copy
    for (int i = 0, count = result.length; i < count; ++i) {
      result[i] = this.content[i].clone(); //defensive copy
    }
    return result;
  }
}


Main.java:
The last step is to update the Main class to now refer to our new FrameFactory. The edits here ought to be obvious (and if not, you can observe them in bitbucket.org/Mercurial SCM in the Eclipse workspace):

package com.blogspot.fromjavatoscala.life.java;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Main {

  public static void main(String[] args) {
    List<String> frames = new ArrayList<String>();
    Frame frame = FrameFactory.firstRandom(25, 25, new Random(0));
    String output = displayFrame(frame.getContent());
    frames.add(output);
    printOutput(0, output);
    boolean finished = false;
    int i = 0;
    while (!finished) {
      frame = frame.next();
      output = displayFrame(frame.getContent());
      finished = frames.contains(output);
      if (!finished) {
        frames.add(output);
        printOutput(i + 1, output);
      }
      ++i;
    }
  }
  private static void printOutput(int tick, String output)
  {
    System.out.println("Tick #" + tick);
    System.out.println(output);
  }
  
  private static String displayFrame(boolean[][] content) {
    String result = "";
    
    for (int y = 0, yCount = content.length; y < yCount; ++y) {
      for (int x = 0, xCount = content.length; x < xCount; ++x) {
        result += (content[y][x] ? "#" : " ");
      }
      result += "\n";
    }
    
    return result;
  }
}

And that's all she wrote. Try it out. The execution results are identical to those of the previous post. The code refactoring to get the Java code closer to an "ideal" state resulted in an almost doubling of the lines of code. This seems pretty consistent with my overall Java coding experience.

The code is located on bitbucket.org/Mercurial SCM as an Eclipse workspace. Don't hesitate to play with it. And I am open to any and all feedback.

What's Next:
My next post ought to be my first post to feature Scala code. I am so looking forward to it while I am simultaneously dreading it. My anticipation comes from the expressive power I can already feel Scala offers (ex: immutability by default). My dread comes from the fear that I will lose my motivation to code in Java ever again. And after 15 years and hundreds of thousands of lines of code with my dearest coding friend, it will be a bittersweet moment to see it begin to fade into my past.

Monday, March 7, 2011

Scala comes to life...

Each time I decide to jump into a new language, I try to find some small simple problem domains within which I can learn to stretch my new wings. It occurred to me the other day that it has been quite some time since I played with Conway's Life Simulation (introduced in "Scientific American" by Martin Gardner in 1970). There are numerous examples life simulators all over the web. And one of my favorite books of all time, "Games of Life: Explorations in Ecology, Evolution and Behaviour" by Karl Sigmund explores it quite liberally and enjoyably.

So, I decided that the quickest way for me to "get going" in Scala was to generate a simple and small version of Life in Java. And then directly convert the class from Java to Scala, treating Scala as "Java without the semicolons". Said more specifically, use Java's imperative style the starting point, a basic clump of digital clay, so-to-speak. And then, over time (and multiple blog entries) I will slowly mold the clay clump into something more useful and interesting.

As a simple recap (which is a copy and paste from the Wiki link - go there to see actual gif animations of the simulation in action), here is the basic domain requirements of Life:
The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, live or dead. Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:
  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overcrowding.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
The initial pattern constitutes the seed of the system. The first generation is created by applying the above rules simultaneously to every cell in the seed—births and deaths occur simultaneously, and the discrete moment at which this happens is sometimes called a tick (in other words, each generation is a pure function of the preceding one). The rules continue to be applied repeatedly to create further generations.
So, my first step is to imagine how I would approach this in Java. My goal is to write a small amount of Java code that achieves this goal. However, it will be quite annoying to have to include all the overhead of having to render the resulting animation. So my very first pass at this problem is to just get the simple rule set working on a relatively simple Java class. The resulting two files are below (and not even very well named). I intend to use github or something equivalent in the future am using bitbucket.org/Mercurial SCM so the code can be viewed in its more natural habitat. However, github was not quite worth the overhead for this first post (which took WAY longer to complete than shows in this resulting "initial" post).

Additionally, while the Java code functions, it is a LONG way from ideal in many ways (OO design, performance, configuration, multi-threading, etc.). However, I figured that it would be more interesting (and fun) if this series showed the evolution of the Java code towards what is considered ideal and just how much boilerplate that ends up requiring. This will create a great basis from which to compare the Scala code, which I hope (and will only be able to do so until I have actually written the Scala code) will be quite a bit shorter with substantially less (if any) boilerplate required.

I am just glad to finally have this post completed. Java code's below. And, the code as an Eclipse workspace is located in a bitbucket.org/Mercurial SCM repository.

Sidenote: What a FREAKING challenge to get code displayed in a blog web page entry. ARGH! Of the +20 hours I spent on this post, +10 of them was chasing all sorts of tangents attempting to figure out how to get the 120 lines of Java code displayed with some semblance of acceptable syntax highlighting. It was worth trying to figure it out, though. I really like the results. And now I get to use it in all future posts, pretty simply, too. If you are interested, here's a link to the solution I eventually found (and an awesome helper).

File 1 of 2: FrameVersion1.java (NOT ideal code - super simple first pass)


package com.blogspot.fromjavatoscala.life.java;

public class FrameVersion1 {
  public static final int[][] NEIGHBOR_OFFSETS = //{x, y} pairs
    new int[][] {
                    {-1, -1}, {0, -1}, {1, -1}
                  , {-1,  0},          {1,  0}
                  , {-1,  1}, {0,  1}, {1,  1}
                };
  
  public static boolean[][] next(boolean [][] content) {
    boolean[][] result = new boolean[content.length][content[0].length];
    //iterate through rows
    for (int y = 0, yCount = content.length; y < yCount; ++y) {
      //iterate through columns of particular row
      for (int x = 0, xCount = content.length; x < xCount; ++x) {
        result[y][x] = calcState(content, x, y);
      }
    }
    
    return result;
  }
  
  private static boolean calcState(boolean [][] content, int x, int y) {
    boolean result = false;
    
    int neighborsAliveCount = 0;
    for (int i = 0, count = NEIGHBOR_OFFSETS.length; (i < count); ++i) {
      int[] offset = NEIGHBOR_OFFSETS[i];
      if (isAlive(content, x + offset[0], y + offset[1])) {
        ++neighborsAliveCount;
      }
    }
    boolean self = content[y][x];
    if (self && (neighborsAliveCount < 2)) {
      result = false; //live cell dies from aloneness (too few live neighbors)
    } else if (    self 
                && ((neighborsAliveCount == 2) || (neighborsAliveCount == 3))
              ) {
      result = true; //live cell lives (sufficient live neighbors)
    } else if (self && (neighborsAliveCount > 3)) {
      result = false; //live cell dies from overcrowding (too many live neighbors)
    } else if ((!self) && (neighborsAliveCount == 3)) {
      result = true;  //dead cell births (precisely enough neighbors)
    }
    
    return result;
  }
  
  private static boolean isAlive(boolean [][] content, int x, int y) {
    boolean result = false;
    
    if (    (y >= 0) && (y < content.length)
         && (x >= 0) && (x < content[y].length)
       ) {
      result = content[y][x];
    }
    
    return result;
  }
}




File 2 of 2: Main.java (NOT ideal code - super simple first pass)

package com.blogspot.fromjavatoscala.life.java;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Main {

  public static void main(String[] args) {
    List<String> frames = new ArrayList<String>();
    boolean[][] content = generateInitialContent();
    String output = displayFrame(content);
    frames.add(output);
    printOutput(0, output);
    boolean finished = false;
    int i = 0;
    while (!finished) {
      content = FrameVersion1.next(content);
      output = displayFrame(content);
      finished = frames.contains(output);
      if (!finished) {
        frames.add(output);
        printOutput(i + 1, output);
      }
      ++i;
    }
  }
  private static void printOutput(int tick, String output) {
    System.out.println("Tick #" + tick);
    System.out.println(output);
  }
  
  private static boolean[][] generateInitialContent() {
    boolean [][] result = new boolean[25][25];
    
    //results in 121 frames before repeating
    Random random = new Random(0); 
    for (int y = 0, yCount = result.length; y < yCount; ++y) {
      for (int x = 0, xCount = result.length; x < xCount; ++x) {
        result[y][x] = random.nextBoolean();
      }
    }
    
    return result;
  }
  
  private static String displayFrame(boolean[][] content) {
    String result = "";
    
    for (int y = 0, yCount = content.length; y < yCount; ++y) {
      for (int x = 0, xCount = content.length; x < xCount; ++x) {
        result += (content[y][x] ? "#" : " ");
      }
      result += "\n";
    }
    
    return result;
  }
}