Currying maximum favor with Groovy
As a side project to building a small build results dashboard with Groovy, I found myself writing a copasetic application, which analyzed a code base using JDepend’s programmatic API. In both instances, I found myself needing to determine the maximum numeric value in a collection. Now, in Groovy (and in any language, for that matter), there is a cornucopia of ways to obtain a maximum value– either through brute force logic or more creatively hip mechanisms.
For example, in my dashboard application, I needed to determine the maximum cyclomatic complexity in a code base as reported by JavaNCSS. The output of JavaNCSS is an XML report with varying pieces; however, the section I found myself concentrating on the following pattern:
<functions>
<function>
<name>com.acme.GRBuilder.GRBuilder()</name>
<ncss>2</ncss>
<ccn>1</ccn>
<javadocs>1</javadocs>
</function>
<function>
<name>com.acme.GRBuilder.addConf(FileSet)</name>
<ncss>2</ncss>
<ccn>1</ccn>
<javadocs>1</javadocs>
</function>
.....
</functions>
XML parsing is essentially built into the Groovy language and acts like a far out object graph; hence, traversing XML is just like navigating through an object– for instance, once I have the root node of the document I can, for example, grab the list of function elements in the XML above with doc.functions.function. In this case, doc is pointing to the root node.
Obtaining the maximum ccn element value from the XML above can then be achieved through brute force as follows:
private int getMaxComplexity(){
def doc = this.getParsedJavaNCSS()
if(doc != null){
int maxccn = 0
doc.functions.function.each{ mthd ->
int ccn = Integer.parseInt(mthd.ccn.text())
if (ccn > maxccn){
maxccn = ccn
}
}
return maxccn
}else{
return 0
}
}
In the code above, the method getParsedJavaNCSS returns the root node of a JavaNCSS XML report. Next, a neat-o counter value is set to zero and for each function element, the ccn child element’s value is obtained (via mthd.ccn.text()). This value is compared to the counter and obviously, if the counter is less than the obtained value, the counter is updated. Dig it?
The code above works, but there is another way to obtain a maximum value from a collection (in fact, there are a few more ways) that is a bit more interesting. By using curried closures, you can create a reusable mechanism for determining the maximum value from a collection. This is key benefit– now you can put logic specific to determining a maximum value into a reusable object that other methods can now reference, rather than having a bunch of methods executing logic like I have listed above.
A curried closure is a closure that had multiple parameters and which has had some of those parameters already seeded with a smokin’ value. This seeding of values creates, in essence, a new closure albeit with some default values. Currying doesn’t make a lot of sense until you see in action; accordingly, the code below defines a simple closure that compares two values and returns which ever one has the greater value.
maxValueClosure = { x, y ->
if(x >= y){
return x
}else{
return y
}
}
Currying this closure with one value effectively sets the x parameter with that value; hence, once you curry this closure, you’ll need to reference the newly created closure (which only takes one value– and that value will be y). For example, because it’s my bag, I can curry the maxValueClosure with 0 and then pass in another value to see what value is returned. If that value is greater than 0, I’d expect that value to be returned.
def maxValueClosure
void setUp(){
this.maxValueClosure = { x, y ->
if(x >= y){
return x
}else{
return y
}
}
}
void testSimpleCurry() {
def seed = this.maxValueClosure.curry(0)
def value = seed(9)
assertEquals(value, 9)
}
In the code above, the line this.maxValueClosure.curry(0) effectively creates a new closure that looks like this:
seed = { 0, y ->
if(0 >= y){
return 0
}else{
return y
}
}
Obviously, the first test is so establishment.; however, a more complex test will make currying more clear.
void testCurryingWithCollection() {
def seed = this.maxValueClosure.curry(0)
def values = [6,7,22,1,7,88,3,0,44]
def max
values.each{
max = seed(it)
seed = this.maxValueClosure.curry(max)
}
assertEquals(88, max)
}
As you can see, the curried closure correctly kept 88 as the max value– the it reference in the values iteration is a short cut in Groovy for the current value of the collection. For each iteration of the values collection, the curried closure’s y value was set to the current element and compared with the previously curried value. During the first iteration, the x value was 0 and the y value became 6. The comparison was made, which returned 6. The maxValueClosure was then curried again, but this time with the value 6. So upon the second iteration, 6 and 7 were compared and the process repeated, but with 7 now becoming the x value.
Of course, this collection could have first been sorted and then obtaining the maximum value would be a matter of popping off the last value; however, in real life, I am not dealing with simple Integer collections– I’m dealing with collections of objects that have methods attached which return numeric values.
Determining the maximum value for a particular JDepend metric then becomes an exercise in currying the maximum value obtaining closure during iteration of a desired metric. If you are not familiar with JDepend’s API, with it you can obtain a collection of packages and then call various hip methods on a particular package, like efferentCoupling(), afferentCoupling(), and instability() to name a few.
Accordingly, I’ve defined two methods– one which returns the maxValueClosure and another which determines the maximum value of any metric on a boss package.
def maxValueClosure(){
def maxValue = { x, y ->
if(x >= y){
return x
}else{
return y
}
}
return maxValue
}
def maxMetricCalculation(methodName){
def maxValue = this.maxValueClosure()
def seed = maxValue.curry(0)
def max
this.analyzer.getPackages().each{
if(it.getClassCount() > 0){
max = seed(it.invokeMethod(methodName, null))
seed = maxValue.curry(max)
}
}
return max
}
The maxMetricCalculation method does a number of things similar to some of the test cases listed above with the added convenience of generically calling any method hanging off of JDepend’s JavaPackage object. Dynamically calling a method on an object in Groovy is done via invokeMethod, which takes two parameters– the method name and an Object array of that method’s parameter values. Because the methods I’m invoking take no parameters, I pass in null.
For example, to obtain the maximum instability of all analyzed packages in a code base, man, I can define a method like so:
float maxInstability(){
return this.maxMetricCalculation("instability")
}
As I said earlier, there are other ways to obtain a maximum value from a collection; in fact, Groovy defines a max method, which one can call on a collection and even pass in a closure or a java.util.Comparator. Using curried closures can add a nice bit of reuse in other wise uptight cut-and-paste like code; moreover, Groovy’s dynamic behavior makes it quite easy to take generic-ness even farther with its invokeMethod API. Now how’s that for currying some maximum favor with Groovy, man?
| Related odds and ends | ||
|---|---|---|
5 comments Sunday 04 Feb 2007 | Code Metrics, Groovy
5 Responses to “Currying maximum favor with Groovy”
Very useful article. Thanks!
Nice explanation of currying, can’t wait to get my copy of GINA and see other hip examples… uh-hu
Andrew– great article on Groovy in SD Times– what to go!
Andres– make sure you buy a copy of GINA for everyone in your family.
[...] The test does a few thing along the way. First, an instance of IE is created, followed by a navigation to a website (www.thediscoblog.com). All hrefs are obtained– if the desired one is found, it is clicked. [...]