August 20, 2008

Handling nulls

There's been a bunch of posts about handling nulls in Scala (and even Java), so let's throw one more into the mix.

This morning, I've been writing some code to read test data from the filesystem, using resources. Following David's lead on showing Java-Scala code, here's a typical Java take on it, note that I need to handle the case of reading the file in IntelliJ differently than I do in the build (IntelliJ now places resources in a subdirectory per module):


def dataFile(path: String): FilePath = {
val resource = getResource(path)
if (resource == null) {
val intellijResource = getResource("furnace/" + path)
if (intellijResource == null) {
error("No resource found at '" + path + "' or 'furnace/" + path + "'")
} else {
intellijResource
}
} else {
resource
}
}

def getResource(path: String) = Foo.getClass.getResource(path)



Now, here's the code rewritten using Option for handling a null returned from getResource (apologies for formatting). I'm using Scalaz's OptionW, as it provides a nice (implicit) conversion from null to an Option (onull) and for throwing an error on None (err). As an aside, these would make a fine addition to the standard API.


def dataFile(path: String): FilePath = dataFileFromAntBuild(path)

def dataFileFromAntBuild(path: String) = getResource(path).getOrElse(dataFileFromIntelliJ(path))

def dataFileFromIntelliJ(path: String) = {
val intellijPath = "furnace" + path
onull(getResource(intellijPath)).err("No resource found at '" + path + "' or '" + intellijPath + "'")
}

def getResource(path: String) = Foo.getClass.getResource(path)



This code is nicer than the first as it explicitly shows that you're sequencing through the nullness and is much more concise (we could make it more concise too if we wish).

For those still stuck in Javaland, there's always Functional Java's Option to achieve a similar thing (though with more verbosity).

No comments: