i have same problem in java interoperability woes scala generics , boxing, don't think solution there work me because require modification third-party code.
specifically, from java (say myjavaclass) i'm trying extend scala class (myscalaclass) extends com.twitter.app.app. app extends com.twitter.util.closeawaitably, , in turn extends com.twitter.util.awaitable.
awaitable // trait `result` defined ^-closeawaitably // trait impl of `result` ^-app // trait no mention of `result` ^-myscalaclass // abstract class no mention of `result` ^-myjavaclass // trying guy compile // , expects impl of `result` all when extending myscalaclass writing myjavaclass, get
[error] myjavaclass.java:[11,8] myjavaclass not abstract , not override abstract method result(com.twitter.util.duration,com.twitter.util.awaitable.canawait) in com.twitter.util.awaitable
i figured have implement result reason, do, in myjavaclass:
public void result(com.twitter.util.duration d, com.twitter.util.awaitable.canawait c) {} now get
[error] return type void not compatible scala.runtime.boxedunit
changing method to
public boxedunit result(com.twitter.util.duration d, com.twitter.util.awaitable.canawait c) {return boxedunit.unit;} results in
[error] return type scala.runtime.boxedunit not compatible void
what heck... start googling. answer java interoperability woes scala generics , boxing seems scala generates java-incompatible bytecode in situation, , hack around problem if had control of of twitter classes (i think closeawaitably) genericize [u <: unit] , return ().asinstanceof[u] in original method implementation trick scalac admitting possibility of "some not-exactly-unit type" (though i'm not totally clear on how works).
i don't have control on twitter classes, myscalaclass , myjavaclass. i don't care the result method - want able extend myscalaclass myjavaclass, implementing abstract methods defined in myscalaclass. it's worth, i'm using scala 2.10.4, jdk 1.8, , (twitter) util-core_2.10 6.22.0, , in case relevant: don't know why it's requiring me implement result in first place. scala class inheriting myscalaclass doesn't have implement method, , builds fine.
how can around this? playing.
you can use similar trick scala's part right, javac still gets confused because it's looking things "wrong" rather right. (the jvm looks right, runs fine.)
the gory details follows.
the twitter hierarchy can simplified follows:
package test trait a[+z] { def z(): z } trait b extends a[unit] { def z() = () } trait c extends b {} now, when write class, don't extend c. instead, you
package test abstract class d[u <: unit] extends a[u] c { override def z: u = (this: b).z.asinstanceof[u] } abstract class e extends d[unit] {} where e takes place of myscalaclass. (and z result.)
now, extends-unit trick, signatures java possibly want present:
$ javap test.b public interface test.b extends test.a{ public abstract void z(); } $ javap test.d public abstract class test.d extends java.lang.object implements test.c{ public scala.runtime.boxedunit z(); public java.lang.object z(); public void z(); public test.d(); } void z not abstract more! in fact, nothing is.
but javac still isn't happy.
package test; public class j extends e { public j() {} } $ javac -cp /jvm/scala-library.jar:. j.java j.java:3: test.j not abstract , not override abstract method z() in test.b um...javac, yes does?
and if make j abstract itself, explains real problem is:
j.java:3: z() in test.d cannot implement z() in test.b; attempting use incompatible return type found : scala.runtime.boxedunit required: void that is, if 2 methods differ return type, , it's not java-sanctioned generic object vs something-else, javac won't find correct one.
this looks me javac bug more scalac one. unfortunately, leaves unable implement classes in java.
as workaround, can (awkwardly) use composition linking 2 classes together.
java:
package test; public interface { public void dothing(); } then scala:
package test trait a[+z] { def z(): z } trait b extends a[unit] { def z(): unit = println("ok") } trait c extends b {} class d extends c { private var myi: def = myi def bind(newi: i) { myi = newi } def dojavathing = i.dothing } then java again:
package test; public class j implements { public static d d; public j(d myd) { d = myd; d.bind(this); } public void dothing() { system.out.println("works!"); } } which @ leasts let switch , forth whenever need to:
scala> new test.j(new test.d) res0: test.j = test.j@18170f98 scala> res0.dothing works! scala> res0.asscala.dojavathing works! scala> res0.asscala.asjava.dothing works!
Comments
Post a Comment