To splat or not to splat, that is the question.
In Java to unpack an array's values into separate variables you would need to do something like the following:
burgers = [:hamburger, :bocaburger, :gardenburger, :turkeyburger] t = burgers u = burgers v = burgers w = burgers
In the Ruby mindset this would look more like the following:
burgers = [:hamburger, :bocaburger, :gardenburger, :turkeyburger] t, u, v = *burgers # t=>:hamburger, u=> :bocaburger, v=>:gardenburger t, u, v, w = *burgers # t=>:hamburger, u=>:bocaburger, v=>:gardenburger, w=>:turkeyburger t, u, v, w, x = *burgers # t=>:hamburger, u=>:bocaburger, v=>:gardenburger, w=>:turkeyburger, x=>nil
Think of * (or splat) as the Ruby way of unpacking the elements of an Array into separate variables in Ruby. This brings me to an even nicer example. Many moons ago, when I was working on a Java/J2EE project, I found a piece of code that looked something like the following (except it has been Rubyfied for this blog entry so that I do not get sued for sharing outrageously fantastic proprietary code with the public - ok, ok….even lawyers would understand this couldn't be called outrageously fantastic even in a parallel universe):
class RunnableWithParams << Thread def initialize(param1) @param1 = param1 end def initialize(param1, param2) @param1 = param1 @param2 = param2 end def initialize(param1, param2, param3) @param1 = param1 @param2 = param2 @param3 = param3 end def run # some code the uses param1, param2, etc. - in Java this was an empty method body or abstract - can't remember end end
Rubifying the the code sure does take some of the sting out of it, but you can probably still feel my initial pain when I realized what kind of code I was inheriting.
The class name and the variables are in fact the same as the original
code. The problem this tried to solve, which I suppose it did solve in
a stupid way, was to allow Java code to pass parameters over to the
thread's logic (which, at least, at the time was not possible to do)
in the context of an anonymous class implementation of the method. Now
if you wanted to pass in 4 parameters, you were out of luck OR you had
to beg the core framework people to add that constructor OR you had to
do an ugly JAR patch hack and put your own implementation of
RunnableWithParams class ahead of the core framework JAR in your
CLASSPATH. They were all pretty ugly scenarios. Of course, you could
pass in a List or Map instance, but that really isn't the point.
The most obvious optimization to the code from a readability, extensibility and utility perspective would be to pass in a list to the class's constructor and use elements in the list in the run method logic. However, Ruby provides a nicer way of doing things from the perspective of the client code:
class RunnableWithParams << Thread def initialize(*params) @params = params end def run # needs to be defined by clients end end
The client code for using this class would look like the following:
rwp = RunnableWithParams.new param1, param2, param3, param4 # instead of the initially optimized suggestion, where the client code would look like the following rwp = RunnableWithParams.new [param1, param2, param3, param4]
In my view the first line of the snippet above is slightly superior because it is more natural in the way it reads. Again, different people will have different views on this perhaps, but both lines of code provide a decent solution.