Angenommen, ich habe dieses Scala-Merkmal:
%Vor%Die Bereitstellung einer Java-Implementierung ist einfach:
%Vor%Beginnen wir nun mit einem generischen Merkmal:
%Vor% Der obige Ansatz funktioniert nicht, da die Einheit x
returns jetzt eingerahmt ist, aber die Problemumgehung ist einfach genug:
Angenommen, ich habe eine Implementierung mit x
auf der Scala-Seite definiert:
Ich weiß, dass ich dieses x
von Java nicht sehen kann, also definiere ich mein eigenes:
Aber das explodiert:
%Vor%Und wenn ich den Trick der abstrakten Klasse, der Delegierten auf Super-Charakter, versuche:
%Vor%Und dann:
%Vor%Es ist noch schlimmer:
%Vor% (Beachten Sie, dass diese Definition von JQux
nur funktionieren würde, wenn Baz
Foo[Unit]
nicht erweitert hätte.)
Wenn du dir ansiehst, was javap
über Qux
sagt, ist es einfach seltsam:
Ich denke, die Probleme hier mit Baz
und Qux
müssen Scalac-Bugs sein, aber gibt es einen Workaround? Ich interessiere mich nicht wirklich für den Baz
-Teil, aber gibt es irgendeine Möglichkeit, die ich von Qux
in Java erben kann?
Sie sind keine Scalac-Käfer; es ist, dass der Scala-Compiler in Ihrem Namen hart daran arbeitet, den Unterschied zwischen Prozeduren und Methoden zu packen, und der Java-Compiler nicht.
Für die Effizienz und Java-Kompatibilität werden Methoden, die Unit
nicht-generisch zurückgeben, tatsächlich als Prozeduren implementiert (d. h. der Rückgabetyp ist void
). Dann wird die generische Implementierung implementiert, indem die void
version aufgerufen und BoxedUnit
zurückgegeben wird.
Das Problem ist, dass javac dasselbe für Sie mit spezifischen vs. generischen Object
-abgeleiteten Rückgabetypen macht, aber nicht die Object
- void
-Kreuzung versteht.
Das ist eine Erklärung. Es gibt eine Problemumgehung, obwohl es die Scala-Hierarchie verkompliziert:
%Vor% Nun haben Sie Scala gezwungen, die Möglichkeit eines nicht-genau- Unit
Rückgabetyps zu berücksichtigen, damit BoxedUnit
für die Rückgabe beibehalten wird; und Baz
verwirft diese Möglichkeit, aber es erzeugt kein neues void x()
, um Java zu verwirren.
Das ist fragil, um es milde auszudrücken. Es kann aber auch ein Problem für die Java und Scala Teams sein: Java ist nicht glücklich, solange die BoxedUnit
Version da ist; es wird aktiv durch die void
version genervt. (Sie können eine abstrakte Klasse mit beiden erzeugen, indem Sie zweimal von Foo erben; da es nicht funktioniert, sind die Details unwichtig.) Scala könnte es alleine schaffen, indem es geänderten Bytecode mit einer zusätzlichen BoxedUnit-Methode überall dort ausgibt, wo Java es erwartet. ..nicht sicher.