Scala Corner Case#1: Implement Method of Java Interface with Type Parameter Omitted by It’s Sub-Clas

Caoyuan Blog - - February 21, 2009

The progress of rewriting Erlang plugin for NetBeans in Scala has reached a phase, that the Editor itself works smooth and better than ErlyBird now, the next step is to integrate an Erlang project management and index the modules/functions of OTP/project to provide smart auto-completion.

Now Scala has been proved that it can be integrated into an existed large Java based framework (NetBeans IDE here) without no much problems, I’ll begin to rewrite Scala plugin in Scala soon.

Although in most cases, Scala can call existed Java code or classes smoothly, there are still some corner cases. I’ll record these corner cases in blogs. Here’s the first one which I also posted on scala-user mailing-list, but have not yet got final answer.

Let’s begin with a detailed example:

There is a Java interface A:

public interface A<T extends String> { void run(T t);
}

Which has a type parameter <T extends String> and abstract method run(T t)

Then a Java abstract class B extended A. But, B, as it, omitted type parameter from A. This is unsafe but valid in Java:

public abstract class B implements A { public String me() { return "I'm B"; }
}

Assume above classes A and B have been compiled under javac, and packed in a jar library, and I can not patch it anymore. Now I need to write a class S in Scala which should extend B:

class S extends B { override def run[T <: String](t:T) = {println(t)}
}

scalac will complain as:

/Users/dcaoyuan/NetBeansProjects/ScalaTestCase/src/S.scala:1: error:
class S needs to be abstract, since method run in trait A of type
(T)Unit is not defined
class S extends B {
/Users/dcaoyuan/NetBeansProjects/ScalaTestCase/src/S.scala:3: error:
method run overrides nothing def run[T <: String](t:T) = {println(t)}

I than tried “forSome” type:

class S extends B { override def run(t:T forSome {type T <: String}) = {println(t)}
}

The code still did not work.

It seems that, since B omitted A‘s type parameter T, I have no way to get what is T, and can not successfully implement “run(T t)” method.

I also tried other forms of “forSome” usages, and always failed.

But I think Scala can always be saved with mixed Java/Scala code in such corner case, that’s what I believed. So, I thought about it later when my brain was spare, and finally got a solution:

I wrote another Java abstract class B1 which extends B and pretended to have implemented “run(T t)”, but actually called another new abstract method “runImpl(String t)”

public abstract class B1 extends B { public void run(String t) { runImpl(t); } public abstract void runImpl(String t);
}

Now I can let Scala S extends B1 and implement “runImpl(String t)” instead of extending B and implementing “run(T t)”.

class S extends B1 { override def runImpl(t:String) = {println(t)}
}

Yes, scalac won’t complain about “runImpl(t:String)” at all, and I got S successfully extends B by bridge class B1.

But I still hope scalac can resolve it directly, with a warning message instead of failing to compile it.



Categories: Blogs  Caoyuan Blog  

Comments

No comments so far, you could be the first.
anonymous avatar

JOIN FREE-Make Money by taking Paid Survey , its simple company pays just for sharing your opinion. World wide offer Join FREE Make money by Paid Survey

Posted by Make Money- Join Free on 03 Aug 2009 at 11:37



 


Add comment

Name:

Email:

URL:

Smileys

Remember my personal information

Notify me of follow-up comments?