May 13, 2009

Parser surprise

1.toString works fine

-1.toString saz " error: ';' expected but '.' found."

need to use (-1).toString

February 26, 2009

class what?

I'm a little annoyed that this doesn't work:

scala> class Foo
defined class Foo

scala> object Thing extends Foo
defined module Thing

scala> val set = scala.collection.immutable.Set[Class[_ <: Foo]](Thing.getClass)
<console>:6: error: type mismatch;
found : java.lang.Class[?0] where type ?0
required: Class[_$1] forSome { type _$1 <: Foo }
val set = scala.collection.immutable.Set[Class[_ <: Foo]](Thing.getClass)
^

I'm sure it's probably a java compatibility thing, but shouldn't the class of an object of type T return a class of type Class[T]?

January 19, 2009

Confused by cons

while learning how to use lists:

val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo :: threeFour //forgot one ":", I really meant to ":::" (concatenate)
val filteredList = oneTwoThreeFour.filter(n => n > 1)

scalac informed me:

Error:Error:line (16)error: value > is not a member of scala.this.Any
val l2 = oneTwoThreeFour.filter(n => n > 1)


Commenting out the offending line and replacing it with

println("oneTwoThreeFour " + oneTwoThreeFour)

yields

oneTwoThreeFour List(List(1, 2), 3, 4)


which clearly shows that the first element is not an Int.

However, the following line compiles:

val filteredList = oneTwoThreeFour.filter(n => n == 1)

probably because '==' is defined for scala.this.Any

December 4, 2008

Pattern Guards fooled by null

A sadness:

Pattern guards don't handle nulls well, and, also, introducing a pattern guard appears to make a default _ not match on null values:

scala> def guard_fails(s: String) {
| s match {
| case s: String if s == null => println("null")
| case s: String if s != null => println("s=" + s)
| case _ => println("default")
| }
| }
guard_fails: (String)Unit

scala> guard_fails("test")
s=test

scala> guard_fails(null)
scala.MatchError
at .guard_fails(:5)
at .(:6)
at .()
at RequestResult$.(:3)
at RequestResult$.()
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMeth...
scala>

scala> def guard_fails2(s: String) {
| s match {
| case s: String if s != null => println("s=" + s)
| case _ => println("default")
| }
| }
guard_fails2: (String)Unit

scala> guard_fails2("test")
s=test

scala> guard_fails2(null)
scala.MatchError
at .guard_fails2(:5)
at .(:6)
at .()
at RequestResult$.(:3)
at RequestResult$.()
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMet...
scala>

To code this match defensively, you have to define a null pattern explicitly:

scala> def ok(s: String) {
| s match {
| case s: String if true => println("s=" + s)
| case null => println("null")
| case _ => println("default")
| }
| }
ok: (String)Unit

scala> ok("test")
s=test

scala> ok(null)
null

scala>

October 24, 2008

Scala RichString is not comparable to String

A sadness:
val r: scala.runtime.RichString = "1"
val s: String = "1"
if (r == s) {
println("ok1")
} else {
println("sad1")
}

if (s == r) {
println("ok2")
} else {
println("sad2")
}

if (s.equals(r)) {
println("ok3")
} else {
println("sad3")
}

if (r.equals(s)) {
println("ok4")
} else {
println("sad4")
}

Will print:
sad1
sad2
sad3
sad4

This isn't as sad as:
sad1
ok2
sad3
ok4
which would precipitate Robey's "ultimate sadness".

I got into this state by adding a .drop to a String, and chaos resulted. The details are tangentally described in: http://www.nabble.com/String-and-RichString-equality-td14888607.html

Still, this is another thing to keep in your head when coding along. I suppose it's best to coerce RichStrings back to Strings immediately, so as not to allow RichStrings to propagate too far.

October 13, 2008

NumberFormatException

scala> "true".toBoolean
res1: Boolean = true


That's pretty cool. Does it work for "false" too?

scala> "false".toBoolean
res1: Boolean = false


Yeah! Awesome! How does it handle other values, I wonder?

scala> "1".toBoolean
java.lang.NumberFormatException: For input string: "1"


... Err, what?

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).