talkingCode

Archive for the scala category

Mysterious ClassCastException from Scala

posted by codders in scala

So here’s one that’s got me thinking. I think this is a fairly straightforward use case, but maybe I’m doing something odd. I have an application where I’m putting objects in to a hash and I want to be able to pull them out with the “correct” types. Which is to say I want to be able not to have to cast the objects on their way out but rather have their types inferred by their use context.

The following code compiles. There’s a method where I’m putting the type hints in, a method where I’m not, and a method where I’m passing the retrieved hash value directly to an explicitly typed function. In all three cases, at least in principle, the runtime types should match – I’m putting in a String, I expect a String out the other side.

There is, so we’re clear, a runtime cast (call to asInstanceOf), but this is where I’m expecting the developer using my class to be right. And where they’re right, what I don’t expect is a ClassCastException.

import scala.collection.mutable.Map

object Main {
  def printIt(optString: Option[String])
  {
    optString match
    {
      case x: Some[_] => println("Got: " + x.get.substring(0,2))
      case None => println("Got nothing")
    }
  }

  def withInferredType(token: Token)
  {
    println("\n--- With Inferred Type ---")

    val fish = token.get("fish")
    printIt(fish)
  }

  def withoutExplicitType(token: Token)
  {
    println("\n--- Without Explicit Type ---")

    val fish = token.get("fish")
    fish match
    {
      case x: Some[_] => println("Got: " + x.get.substring(0,2))
      case None => println("Got nothing")
    }
  }

  def withExplicitType(token: Token)
  {
    println("\n--- With Explicit Type ---")

    val fish = token.get[String]("fish")
    fish match
    {
      case x: Some[_] => println("Got: " + x.get.substring(0,2))
      case None => println("Got nothing")
    }
  }

  def main(args: Array[String])
  {
    val token = new Token
    token.put("fish", "cat")
    withExplicitType(token)
    withInferredType(token)
    withoutExplicitType(token)
  }
}

class Token()
{
  private var elements = Map[String,Object]()

  def get[A <: Object](key: String): Option[A] =
  {
    for (val value <- elements.get(key))
      return Some(value.asInstanceOf[A])
    return None
  }

  def put[A <: Object](key: String, value: A)
  {
    elements.put(key, value)
  }
}

resulting in:

 scalac Token.scala && scala Main

--- With Explicit Type ---
Got: ca

--- With Inferred Type ---
Got: ca

--- Without Explicit Type ---
java.lang.ClassCastException: java.lang.String cannot be cast to scala.runtime.RichString
        at Main$.withoutExplicitType(Token.scala:29)
        at Main$.main(Token.scala:52)
        at Main.main(Token.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
        at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

In all three cases I’m doing the same thing with the same data. In the ‘Inferred Type’ case, it’s actually doing the thing I want in production. But all three cases compile and one throws a ClassCastException – I had very much hoped that the type system would pick me up on the broken case.

What am I doing wrong, lazyweb? Any comments greatly appreciated.

Considered Harmful

Morning. I’ve had a think about it and as usual with me writing about Scala, it’s my mistake rather than the language’s. What I’d hoped to achieve was something like duck-typing where I could pull something out of the hash and use it as whatever made sense in the code. Static type inference doesn’t work this way though.

In the above code, in the two cases where I was constraining the type, it works fine. In the case where I don’t constrain the type, Scala can legitimately choose any type that implements substring; in this case it chose RichString, which happens not to be the type I put in to the hash. In general, this is a pretty dangerous approach – what I want is for the type system to force me to nominate a type for the result of the get before I use it.

Turns out the way to do this is to have get return Object and use asInstanceOf at the call site. C’est la vie.

Abstract Type Members – Augmenting Scala classes

posted by codders in code, java, scala

So, Scala’s cool.

About a month ago, a colleague was whining about having to write Java and it was hard not to sympathise. He’s a Python man, and Java’s Kingdom Of Nouns can seem a little clumsy. Sometimes, you just want to map{}, and trying to do that in Java can leave you feeling dirty.

There are proposals for first class functions and closures in JavaNeal Gafter is your man there. They look fun n’all, but they are apparently a little way off. What I needed in order to silence my colleague was less irritating Java in production straight away. In order to satisfy the needs of m’colleague, m’self and m’company I would need a couple of things.

Pour lui

  • Concise variable declarations – none of this
    Map<String,List<Integer>> map = new HashMap<String, List<Integer>>()

    nonsense

  • Functions as first class values
  • Excellent library support

Pour moi

  • Strong, static typing
  • Eclipse integration
  • Monads. Everybody loves monads

For practicality’s sake

  • Maven integration
  • Interoperation with the existing Java code base

I had a look on Wikipedia for a suitable JVM language since that would ensure the easy interoperation and give us a decent set of libraries. It turns out Scala has everything we need. It’s mixed paradigm functional / object-oriented, it’s got a Hindley-Milner style type inference system, and it’s got a really active community. The eclipse/maven integration isn’t quite there yet, but it gets much better as you get closer to the bleeding edge.

Some Code

There have been too many cool things to mention really, but here’s the first one that seemed apt for a blog post. Scala has some nice XML support, but lacks some of the functions you might like on an XML Node like, for example, ‘getAttributeValue(attributeName)’. In Haskell, you could define a new typeclass and create an instance for Node. In Java / C++ you could delegate (if you like pain). In Ruby, you could mixin. The answer in Scala appears to be… an Abstract Type Member.

Disclaimer:
I don’t know what the right answer actually is, but this works and seems kinda cool

import scala.xml.NodeSeq
import scala.xml.Node

object XmlTest
{
  implicit def nodeToNodePlus(node: Node):NodePlus =
  {
    return new NodePlus { type T = Node; val init = node }
  }

  abstract class NodePlus
  {
    type T <: scala.xml.Node
    val init: T
    private var value: T = init

    def getAttributeValue(name: String): String =
    {
      return value.attribute(name).get.first.text
    }
  }

  def main(args: Array[String])
  {
    println("Hello")
    val xmlDoc = <hi><hello id="world"/></hi>
    val hello = (xmlDoc\"hello").first
    println(hello.getAttributeValue("id"))
  }
}

The mechanics of what's going on there are... err... pretty opaque to me. But to break that down a little:

  • An object is a singleton class, equivalent in most senses to a static class in Java.
  • An implicit is a function from A to B which the compiler will use whenever inference tells it that you need a B but have an A (yes, evil, but okay if used carefully).
  • type T is an Abstract Type Member. I think.
  • <: is a subclass restriction

... all of which allows me to introduce a new function to an existing class without access to that class's constructor. Handy.

That's probably garbage. No doubt I'll find out that's not the way to do it or that it won't do what I expect, but it seems to work. The take-away is that Scala is an easy transition from Java, is much prettier and cooler, and that I can't think of a good reason to write any more Java code.

... having slept on it...

Ah. You see. What I did there was... I got carried away. My NodePlus class is actually no better than a wrapper - I can't actually do any Node operations on it. The implicit mechanism makes it look like I can, but I can't. And the Abstract Type Member was a bit of a red herring. What the Abstract Type Member is doing is letting me parameterise my type which is, I guess, a kind of useful. Given that Scala types accept formal parameters, though, it's not completely clear how much win is involved.

I'll let you know if I find out how to do the thing I actually want to do.

Recent Posts
Recent Comments
About Us
jp: works like a charm! thanks!...
Blake: Check this out: http://bugs.adobe.com/jira/browse/SDK-28016...
Boydell: Wow. That was it. You are the only one that had it figured out, and I looked at many...
mark van schaik: thanks! was using a beta SDK version for a production app, which stopped working over...
Sebastian: Steve, I find most asynchronous programming to be incredibly painful. Haskell's appro...

This is the personal blog of a professional software engineer. This site and the views expressed on it are in no way endorsed by the RIAA.