views:

80

answers:

2

Attempting to implement code similar to that found in the higher-order-function example from http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6

val button = new JButton("test")
button.addActionListener{ e:ActionEvent => println("test") }
add(button)

leads to the following

error: type mismatch;
found   : (java.awt.event.ActionEvent) => Unit 
required: java.awt.event.ActionListener
   button.addActionListener{ e:ActionEvent => println("test") }
                                           ^

This is true at least with Scala compiler version 2.7.6.final on my system. I am able to achieve what I want in the Java-style way of explicitly implementing an anonymous ActionListener.

button.addActionListener( new ActionListener() {
  def actionPerformed(e:ActionEvent) { println("test") }
})

As far as I understand, Scala should be able to use duck-typing to render this explicit implementation of ActionListener unnecessary; so why isn't it working here? I have next to no practical experience of duck-typing at this point.

+4  A: 

Scala isn't duck-typed. It has optional, explicit structural-typing, but that doesn't have anything to do with why your code does not work.

Your code does not work, because JButton.addActionListener expects an ActionListener as its argument, not a function. Even if scala were ducktyped, you couldn't just pass a function because the same methods available on an ActionListener are not available on a function.

Note that the article says "Let’s assume for one blissful moment that we could rewrite Swing to take full advantage of Scala’s syntax", i.e. the article does not claim to show you actual code that works.

However scala does have it's own swing package (scala.swing) which contains classes which are more "scalaish" to use than their java equivalents.

sepp2k
Ah, that quote from the article is indeed pertinent. I had a feeling asking a question in public was bound to expose some basic reading comprehension failure on my part...Still, your answer is informative. Thanks.
PeterT
+7  A: 

Duck-typing has nothing to do with the reason that your code doesn't work. It is because Scala's type system doesn't provide implicit conversion between interface type and function type by default. However, if the following implicit conversion is defined, your code works correctly.

implicit def toActionListener(f: ActionEvent => Unit) = new ActionListener {
  def actionPerformed(e: ActionEvent) { f(e) }
}

This implicit conversion provides conversions from (ActionEvent => Unit) to ActionListner.

kmizu
Not as fanboyism, but it's worth noting that both Groovy and the various Java closure proposals did include implicit conversions from appropriate function types to single method interfaces. This is very convenient for interfaces like Runnable or Comparable. In Scala, you either need to do this conversion by hand, or rely on pimped libraries to do it.
Dave Griffith
@Dave Yes... if the type doesn't match, auto-cast it. I think it should be obvious why Scala didn't choose this way.
Daniel
Oh, certainly. It only makes sense for Groovy and Java because they don't include any good ways of extending existing libraries, so they need this auto-conversion to make working with legacy Java non-painful. Scala has pimps for legacy libraries, and new libraries should be (and are being) written to favor functional forms over single-method interfaces.
Dave Griffith