tags:

views:

115

answers:

3

My implementation of a getHandler method, which is defined on a Java interface, has failed, and I don't know why. Here is the method signature:

<H extends EventHandler> H getHandler( Type<H> type, int index );

My implementation in Scala is:

def getHandler[H <: com.google.gwt.event.shared.EventHandler]
    (aType: Type[H], index: Int): H 
    = new com.google.gwt.event.shared.EventHandler() {}

...but the compiler gives me this message:

type mismatch;  
    found: java.lang.Object with com.google.gwt.event.shared.EventHandler
    required: H

Where have I erred?

+4  A: 

I think it's because your implementation doesn't uphold the contract of the interface. H could be any subtype of EventHandler, determined by the type of the aType argument. But your implementation always returns the same anonymous subtype of EventHandler, regardless of what is passed as the aType argument.

I don't know what a correct implementation would be, but I can't see how this could be implemented without somehow making use of the aType parameter.

Lachlan
+1  A: 

I think this may make it compile:

def getHandler[H <: com.google.gwt.event.shared.EventHandler]
    (aType: Type[H], index: Int): H = {
  val h = new com.google.gwt.event.shared.EventHandler() {}
  h.asInstanceOf[H]
}

It's expecting an H. As Lachlan says, aType probably is needed somewhere.

huynhjl
...and even more succinctly: new com.google.gwt.event.shared.EventHandler() {}.asInstanceOf[H]
David
It might make it compile, but it is a terrible advice. The code is incorrect, and will cause problems if implemented this way.
Daniel
Yes, I agree, as advice it's terrible. I looked at http://www.docjar.com/html/api/com/google/gwt/event/shared/HandlerManager.java.html and decided that I was just going to answer why it does not compile. I feel bad it's the accepted answer.
huynhjl
+3  A: 

Adding to Lachlan's answer I'd like to point out, that simply casting the return type to the expected type may have desastrous effects.

Consider the following implementation where I have used a named class instead of the anonymous inner class from the question:

class MyHandlerA extends EventHandler
class MyHandlerB extends EventHandler

object BadImplementation extends I {
  def getHandler[H <: EventHandler](typ : Type[H], index: Int) = {
    (new MyHandlerA).asInstanceOf[H] // BAD: This asInstanceOf is a lie!
  }
}

The following line will cause a ClassCastException without warning.

val b: MyHandlerB = BadImplementation.getHandler(new Type[MyHandlerB] {} , 0)

So in addition to the cast an implementation will have to ensure that the returned handler is actually assignable to H or return null or throw an exception.

mkneissl