Tuesday, May 31, 2011

The magic of getOrElse

For the last month or so I've been coding in Scala. From time to time I use Option's; they seem pretty handy; it's much nicer to get an Option[T] back instead of a null. I semi-often find myself writing things like:

//where f is a function returning Option[Something]
   val t = f(args) getOrElse 3

Recently I realized (classic lightbulb moment :) that getOrElse actually takes a function as the argument:

def getOrElse [B >: A] (default: ⇒ B): B
  //Returns the option's value if the option is nonempty, otherwise return the result of evaluating default.

Why does this matter? It means that the code passed to getOrElse doesn't run at all (default is not evaluated) if the Option is defined! For example, this code:

object GetOrElseTest {
 def main(args : Array[String]) : Unit = {
  def a() = Some(3)
  def b() = None
  val aV = a getOrElse { println("nothing from a :("); 1 }
  val bV = b getOrElse { println("nothing from b :("); 1 }
  println("aV=%d, bV=%d".format(aV, bV)) 

Will print this output (note that the println for getting a, which is defined, never runs):

nothing from b :(
aV=3, bV=1

That's awesome and really hard to accomplish in Java. Imagine if log4j could do this; suddenly we wouldn't have any issues with things log.debug("a" + objectThatIsExpensiveToToString.toString()) having a runtime cost even when debug isn't enabled because we wouldn't evaluate the function to create a message at all if debug is off.

The new uniforms are pretty snappy eh first officer!

Monday, May 30, 2011

How to print Ivy's cachepath one artifiact per line with Ant

Many moons ago one Andrew Beacock shared how to use to dump out a classpath in a human-readable fashion (see http://blog.andrewbeacock.com/2005/08/pretty-printing-java-classpaths-using.html). The amount of Ant pain this gem saved me back in the day is ... well a lot.

Fast forward to 2011 and we're using Ant with Ivy as our dependency manager. We use Ivy's retrieve Ant task to get our artifacts but how do we print out a simple list of what Ivy got for us? Well, it turns out cachepath can get this for us, optionally filtered if we see fit:

<!-- after a resolve; in our case this target depends on our resolving target -->
    <ivy:cachepath pathid="ivy.cachepath" settingsRef="ivy.settings" />
    <pathconvert pathsep="${line.separator}  "
    <echo>DEPENDENCY LIST</echo>
    <echo>  ${dependency.list}</echo>

This will print something along the lines of:

[echo]   C:\...\.ivy2\cache\org.slf4j\slf4j-api\jars\slf4j-api-1.6.1.jar
     [echo]   C:\...\.ivy2\cache\org.slf4j\jcl-over-slf4j\jars\jcl-over-slf4j-1.6.1.jar
     [echo]   C:\...\.ivy2\cache\org.slf4j\log4j-over-slf4j\jars\log4j-over-slf4j-1.6.1.jar
     [echo]   C:\...\.ivy2\cache\ch.qos.logback\logback-classic\jars\logback-classic-0.9.28.jar
     [echo]   C:\...\.ivy2\cache\ch.qos.logback\logback-core\jars\logback-core-0.9.28.jar

Once in a while this is a lifesaver as it makes it easy to see a simple list of our dependencies. Since we print it out line-by-line it's now nice and easy to grep through and find specific things. Like say what version of the components in such and such a group we are getting.