for all things technical

Ruby vs. Java in Solving The Perfect Shuffle Problem, Part 3 of 3

Prev: The Perfect Shuffle Problem

The Code

Both Java and Ruby based solutions to the Perfect Shuffle Problem are available for download below. In addition to comparing styles, they are informative for anyone learning Ruby with a Java background, or vice versa.

The Java based solution is 82 lines of code, while the Ruby version is 76 lines. Not a huge discrepancy. The character count is quite different though: 1,943 (Java) versus 1,615 (Ruby). Looking at the two code excerpts, we see why.

The Java program’s main loop is shown below.

private long getNumPerfectShuffles() {
int pos = 0;
long totalShuffles = 1;
while( (pos = getFirstUnvisited(pos) ) < _visited.size() ) {
long shuffles = 0;
do {
_visited.set(pos, true);
pos = shuffle(pos);
++shuffles;
} while (!_visited.get(pos));
totalShuffles = lcm(totalShuffles, shuffles);
}
return totalShuffles;
}

If you are used to programming with Java, the verbose aspects of the above code above may not be obvious to you, such as

  • Explicit type declarations.
  • Static typing.
  • Mandatory parenthesis after method names.
  • Mandatory semicolons on each line.

Comparing the preceding Java code to the equivalent Ruby snippet makes the verbosity of Java more obvious.

def get_num_perfect_shuffles
pos = 0
total_shuffles = 1
while (pos = get_first_unvisited pos) < @visited.size
shuffles = 0
begin
pos = shuffle pos
shuffles += 1
end while !@visited[pos]
total_shuffles = lcm(total_shuffles, shuffles)
end
return total_shuffles
end

What I Think

I like the Ruby version more.

I don't care about static typing. The static typing in Java does prevent some bugs. Also I admit that to do any serious development with Ruby I use a unit testing framework. But I've found static typing to prevent only a small minority of bugs, and not even those particularly challenging. So I still need to use unit tests with Java anyways.

I also like not having to place parenthesis, braces and semicolons all over the place.

while (pos = get_first_unvisited pos) < @visited.size
shuffles = 0

will always be easier for me to read than

while( (pos = getFirstUnvisited(pos) ) < _visited.size() ) {
long shuffles = 0;

When Ruby is explicit, I feel it gets it right. Note that in the java version I place an underscore at the beginning of _visited to remember it is an instance variable. That's just my technique. With Ruby, this convention is formally enforced with an at character. So the @ denotes @visited is an instance variable.

Finally, with the above two code snippets I did not even touch upon the deeper features unique to the Ruby language, such as blocks and metaprogramming. Such features have no practical significance in solving The Perfect Shuffle Problem though.

Conclusion and Download

But my preference for Ruby is simply that: my preference. I didn't write this article to convert you into Ruby believer. I hope you will compare and contrast Java and Ruby for yourself.

Please download the Java version here: http://abettermanual.com/wp-content/uploads/2009/09/PerfectShuffle.java

The Ruby version is available here: http://abettermanual.com/wp-content/uploads/2009/09/perfect_shuffle.rb

I hope you found this series of articles informative. I welcome your feedback. Good luck with all your programming endeavors.


Leave a Reply