Over the last couple of days I have been trying to implement the Sharing Problem (Ruby Quiz #65: Splitting the Loot) in Scala. So far I have implemented the greedy pick algorithim and still need to implement a recursive solution that will brute force the edge cases.
However on the way I think I have picked up some important lessons. You can see the code for yourself in the GitHub project related to the problem and the solution (it’s in the Scala directory) but I will be highlighting some of the code in this post.
This was the first set of Scala I’ve done that was actually an attempt to use some of the functional aspects of Scala rather than just porting Java code in a more or less literal and imperative way. After struggling a little bit with the implict return and list concatenation I implemented the greedy heuristic. This is what it looked like (link to the code file).
import gems._
package splitter {
class LootSplitter
object LootSplitter {
def splitLoot(gembag: GemBag, shares: Int): List[GemBag] = {
if((gembag.totalValue % shares) != 0) {
return List[GemBag]()
}
val individualShareValue = gembag.totalValue / shares
var partShares: List[GemBag] = List.make(shares, new GemBag(List()))
gembag.gems.sort(_.value > _.value).foreach((gem: Gem) => {
partShares = partShares.sort(_.totalValue < _.totalValue)
partShares = List(partShares(0) add gem) ::: (partShares drop 1)
})
partShares
}
}
}
}
I was struck initially by how compact this code was, you are looking at about 28 lines of code. However as I was looking at it I began to wonder whether it was concise or just terse. How is someone meant to interpret something like _.value > _.value? I showed it to a collegue and his first reaction was “I don’t know functional languages so I wouldn’t know what this means”.
This was exactly the kind of reaction I was afraid of because I have been converted heavily to the principal of readable code. Someone should be able to scan code and understand, in principle, what is happening here. If they don’t then the cost of maintaining that code is going to be higher and we have actually lost something in the concise syntax.
I decided to try and implement a readable version of the same file which added about 6 lines (only two according to GitHub!). You can read this version here but now I want to throw it open to the public. Is this version actually easier to read? Are things like the underscore variable actually part of the price of comprehending Scala?
In my rewritten version I use some of the nice features of Scala such as first order functions but you still have lines like this:
List(sortedBags(0) add gem) ::: (sortedBags drop 1)
I hope you are reading this as “add a gem to the first sortedBag and make a List of it and then add all the other bags except the first one to the new list” but I am worried that this is far from obvious. Is that because I’ve done something that isn’t idiomatic or is it because actually the operators and the library API are too obscure?
Scala represents a significant evolution of Java in terms of absorbing all the lessons learned during the evolution of the language. When porting Java code I feel far more comfortable with it than when I am trying to create new code that uses the core language libraries. I don’t want to evolve to a new set of problems and best practices that try to avoid them.