Tuesday, 20 April 2010

Scala / TestNG gotcha with result type inference

I recently ran into a Scala / TestNG gotcha that proves how much of a Scala noob I still am (but also the kind of problems you can have with the type inference features).

Scala has two nice features that can make your method definitions very succinct, but as is the case with many of such features, they can cause some problems of their own if you're not careful.
The two features are:

  • result type inference
  • optional return statement

The result type inference allows you not to specify the result type of a method, allowing the scala compiler to infer it:


// the result type is explicitly defined
def getFooWithResultTypeSpecified() : String = {
    return "123"
}

//the result type will be inferred
def getFoo() = {
    return "123"
}

val foo = getFoo()
// foo will be inferred to be a String as getFoo was inferred to returning String.
assertEquals(foo,"123")

The optional return statement is exactly that: it allows you to leave out the actual return statement. The compiler will use the result of the last expression as the result type.

def getFoo() = {
    "123"
}

val foo = getFoo()
assertEquals(foo,"123")

The gotcha I had was in the combination of these features. TestNG considers test methods to be those methods that are both public and void returning. So let's say I start out with he following method:

def testFoo() = {
    val foo = new Foo()
    // if doSomeVoidMethod doesn't fail, it's good
    foo.doSomeVoidMethod()
}
The result type of testFoo is void, so the method will be executed by TestNG. Than you change foo.doSomeVoidMethod to foo.doSomeStringReturningMethod. Now testFoo is inferred to return a String, and the method is no longer executed by TestNG. This was exactly the problem I had, and I spent quite some time figuring out why some of my test methods were no longer being run.


The correct protection against this is always ensuring that your test methods are explicitly declared to return Unit (void) like this:

def testFoo() : Unit = {
    val foo = new Foo()
    // if doSomeStringReturningMethod doesn't fail, it's good
    foo.doSomeStringReturningMethod()
}
The correct protection against this is using procedures instead of functions, like this:
def testFoo() {
    val foo = new Foo()
    // if doSomeStringReturningMethod doesn't fail, it's good
    foo.doSomeStringReturningMethod()
}
Note the missing = that makes all the difference. Thanks to Joey for making that clear.

Technorati Tags:

Posted by cvf at 7:55 AM in Java

Monday, 5 April 2010

There's been an explosion in the ASCII factory.

There's been an explosion in the ascii factory.

I always thought this sentence was reserved for Perl, but I recently discovered that this can unfortunately also be applied to Scala. Scala supports operator overloading (although technically it's not), so we see the good and the bad sides of this.

Representing the good side, you have the parser/combinators library that comes with scala. It implements a DSL that looks very natural if you're already familiar with the BNF form.

The dubious honour for representing the bad side in this case goes to the Dispatch library. I was looking for a library that would allow me to make some calls to a restful service (couchdb in this case), and came upon it.

It has some of the worst abuses of operator I've seen in a while. Look at the following lines you can find in the introduction docs:


import dispatch._
val http = new Http
val req = :/("example.com") / "path"

val rhead = req <:> Map("Cache-control" -> "no-cache")
http(req / "somefile.xml" <> { _ \\ "book" })
val rauth = req as ("user", "secret")
val rquery = req <<? Map("key" -> "value")
val rform = req << Map("key" -> "value")
http(req >~ { _.getLines.foreach(println) })
val rsec = req.secure

Now, I left out the comments above each line that explain what the code does, but that is my whole point. There is now no longer any way for someone not already very familiar with Dispatch to have any idea whatsoever about what that code does. Even if I were to write code using this library, I'm certain that I'd have trouble figuring out what it exactly does again only a week later.

It really feels to me that the author of this library has an innate hatred against the alphabetic part of his keyboard. There's i.m.o. no other justification for letting "<<?" mean "add a query string to the request".
Even a javastyle req.setQuery(Map(...)) would have been much better, rememberable and readable.

If libraries like Dispatch represent how idiomatic scala will be written, I'll be looking for another language to succeed java.

A small bonus :)

("@ , There's been
°!&  0 an explosion
#^a /|\ at the ASCII
`;<  |  factory!!!!
@a  / \

Technorati Tags:

Posted by cvf at 10:29 PM in Java

« April »
SunMonTueWedThuFriSat
    123
45678910
11121314151617
18192021222324
252627282930