Implementing a Kotlin property from a Java interface - java

Consider the following Java interface
interface Foo {
String getValue();
}
In Kotlin, get/set functions are converted to properties, so I would expect the implementation to look like this
class FooImpl : Foo {
val value: String get() = "Hello, World!"
}
But I actually have to implement the method as it is in the interface
class FooImpl {
override fun getValue(): String {
return "Hello, World!";
}
}
Why?

Kotlin makes an explicit difference between methods and properties. They are not considered the same thing; it just so happens that both are compiled down to methods in the end since the JVM doesn't natively support properties. As such, a method cannot implement a property since they're fundamentally different.
The reason why you can't implement a Java getter with a property is the same reason as why you can't implement a Kotlin-defined fun getX(): String with an override val x: String; they're just not compatible.
The confusion here seems to stem from how Kotlin allows you to access Java getters with a property-like syntax, i.e. val foo = obj.x is equivalent to val foo = obj.getX() if the class is defined in Java.
This is strictly a one-way relationship to make Kotlin code that interoperates with Java code slightly more compact and "Kotlin-like"; this syntactical shortcut doesn't extend to implementing the method as if it were a property.
Additionally, if you were to implement a method as a property, that would probably lead to strange effects. Arguably, it would be both a method and a property at the same time, which would not only be weird, but would likely lead to a lot of other unexpected behaviors and edge cases in the language. (For instance, how would it be treated when using reflection?)

Related

Kotlin default implementations from Java

I have an interface in Kotlin that I want to have default implementations so that implementing classes will only have to implement a subset of the methods. Example:
interface PersonInterface {
val firstname: String?
get() = null
val lastName: String?
get() = null
val phoneNumbers: List<String>?
get() = null
val interests: List<List<String>>?
get() = emptyList()
}
This in my understanding would create default implementations for the methods to return null or an empty list or whatever I would have as defaults in general.
But if I create the following class in Java (which I expected it would compile):
public class Employee implements PersonInterface {
}
I get:
Class Employee must either be declared abstract or implement abstract
method getFirstName in PersonInterface
Is it possible to use default interface implementation defined in Kotlin from Java?
According to documentation (https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html):
Starting from JDK 1.8, interfaces in Java can contain default methods. To make all non-abstract members of Kotlin interfaces default for the Java classes implementing them, compile the Kotlin code with the -Xjvm-default=all compiler option
Note: Prior to Kotlin 1.4, to generate default methods, you could use the #JvmDefault annotation on these methods. Compiling with -Xjvm-default=all in 1.4 generally works as if you annotated all non-abstract methods of interfaces with #JvmDefaultand compiled with -Xjvm-default=enable. However, there are cases when their behavior differs. Detailed information about the changes in default methods generation in Kotlin 1.4 is provided in this post on the Kotlin blog.

Does the use of `is` in a when expression over a sealed class result in reflection at runtime?

In Java, if I have a class hierarchy like so:
private interface Foo { }
private class FooBar implements Foo { }
private class FooZoo implements Foo { }
And then I have a function like so:
public int Return0IfFooBarElseIfFooZooReturn1ElseReturn2(Foo foo) {
if (foo instanceof FooBar) {
return 0;
} else if (foo instanceof FooZoo) {
return 1;
} else {
return 2;
}
}
At run time, reflection will be used to determine the type of foo. In an ideal world, we would like to avoid having our code use reflection. In addition, as far as I know, there is no way to create a sealed type hierarchy in Java, meaning you will always need to provide an else branch to have the code compile.
However in Kotlin you can create a sealed type hierarchy, like so:
sealed class Foo {
object FooBar : Foo()
object FooZoo : Foo()
}
And you can then write a when expression to switch on the type and return a value like so:
fun return0IfFooBarElseReturn1(foo: Foo) = when (foo) {
is Foo.FooBar -> 0
is Foo.FooZoo -> 1
}
There is an interesting property about this; namely, there is no need for an else, because the when expression is exhaustively checking the sealed type hierarchy. So, from this property, can the compiler derive enough information in order to compile bytecode which somehow is not going to use reflection at runtime to determine if the passed instance is of a given type?
Or in other words, is there any difference (with regards to reflection) at run time between the Kotlin code above, and the Kotlin code below:
interface Foo
class FooBar : Foo { }
class FooZoo : Foo { }
fun return0IfFooBarElseReturn1(foo: Foo) = when (foo) {
is FooBar -> 0
else -> 1
}
I am asking this, because generally as programmers, we would like to avoid reflection (where possible), but the official Kotlin docs for sealed classes show an example of switching on an instance using is (https://kotlinlang.org/docs/reference/sealed-classes.html). I also do this a fair bit in the code I do at work, and whilst I don't really see any issue with doing it, some co-workers have voiced concerns as it looks like a code smell.
Whatever the compiler does behind the scenes is irrelevant to whether this is good practice. Reflection is code smell when you're using it to micromanage the behavior of objects which could otherwise be taking care of their own behavior through polymorphism.
In the case of sealed classes, you are working with a finite set of classes, so micromanaging their behavior is less arduous, but in my opinion is still a smell if you're doing it outside the file that defines them.
Here's an interesting article about when it makes sense to rely on reflection rather than polymorphism. The TLDR:
Polymorphism only makes sense when the polymorphic behavior is really a behavior of the target. When it's the behavior of the observer, you need runtime typing.
So if your when statement is asking each object to do something or calculate something, it is likely a situation where polymorphism should be preferred. If your when statement is doing something to the objects or needs to sort them in some specific way, the reflection may be more appropriate.
One area where I think it makes sense to use sealed classes in when they are the return value of something that parses a file or something from the Web. Unlike the Expr example where everything can evaluate to a Double, when you read from some unpredictable file, the return value may have an unpredictable type. You might want to sort the return value into a specific handler. Or the return value might be an error that you handle differently than a valid value.
You can also use sealed classes as a better alternative to checked exceptions. By wrapping a result in a class that can be a valid result holder or an error, you force the caller to handle errors if it needs to, or it can bubble them up without the function signature having to know anything about the types of errors it might encounter. Then at whatever level needs to handle the error, it can be unpacked with a when statement.

Kotlin method overloading

This following declaration is legal in Kotlin.
fun foo(): String = "foo_1"
fun <T> foo(): T = "foo_2" as T
As bytecode we are getting:
public final static foo()Ljava/lang/String;
// signature <T:Ljava/lang/Object;>()TT;
// declaration: T foo<T>()
public final static foo()Ljava/lang/Object;
It's also possible to call both of these methods from Kotlin.
The problem comes when I'm trying to call any of them from Java:
ClassKt.foo()
Ambiguous call. Both methods match ...
How to avoid such a problem? How to deal with such methods? What if 3-rd party kt library has same issue?
The example above is a synthetic one.
Why does it work with Kotlin to begin with... In Java having two methods like:
private static String test() {
return "";
}
private static <T> T test() {
return null;
}
would result in a compile time error. And for java devs this is sort of obvious, these methods would have the same type erasure. But this is rule imposed by javac, not by the JVM where this code runs. So javac does not treat two methods as having only a different return type as overloads. Well, kotlin is a different language and since it runs on the JVM (that expects valid byte-code) it allows treating methods with only the return type being different as overloads. I am yet to look at the byte code and understand how that happens; it also seems that this will work only for generic code, so may be type erasure is slightly different in case of kotlin.
Now, things should be obvious why calling such a method from java fails. Kotlin offers a neat solution for this: #JvmName("someDistinctName"). I am not entirely sure how this works under the hood either... yet, though I assume this will create a bridge method.
EDIT
#JvmName will rename the method at the byte-code level.
You can use #JvmName to differentiate the code when it's called from java:
#JvmName("fooString")
fun foo(): String = "foo_1"
fun <T> foo(): T = "foo_2" as T
This will allow calling the String method in Java with ClassKt.fooString(), which resolves the clash.
An easy solution would be writing a helper method in Kotlin and just calling that.
Another way using only Java would be getting a MethodHandle for both methods and using them:
MethodHandle MH_fooString = lookup().findStatic(ClassKt.class, "foo", methodType(String.class));
MethodHandle MH_fooT = lookup().findStatic(ClassKt.class, "foo", methodType(Object.class));
String foo = (String) MH_fooString.invokeExact();
It's not nearly as simple and requires handling exceptions though.

Scala: how to implement a java interface that contains scala "typed" classes without their type parameters

This is a tricky one - I have a java interface that I want to implement in scala:
public interface Foo {
public void bar(scala.Array arr);
}
Is it even possible to implement in scala? when I try:
class FooImpl extends Foo {
override def bar(arr: Array[_]): Unit = ???
}
I get:
Error:(13, 7) class FooImpl needs to be abstract, since method bar
in trait Foo of type (x$1: Array)Unit is not defined
(Note that Array does not match Array[_]. To implement a raw type, use
Array[_])
class FooImpl extends Foo {
The error message is giving you the answer for any generic type other than Array (after replacing the name, of course):
To implement a raw type, use Array[_]
"Raw type" is what Java calls a generic type used without a type parameter and e.g. https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html explains why you should not use them except to interface with now horribly obsolete pre-Java-5 code. So if it is at all an option, you should fix the Java interface in the first place.
Now, why does this not work for Array? It's a special type, which is really built into compiler. Its instances are real JVM arrays, which don't have a common type in Java. So when it's used in Scala code, the compiled bytecode doesn't use scala.Array at all. I guess that it only exists as a JVM type (unlike e.g. scala.Any or scala.Null) to put the static methods there, but all instance methods are defined as throw new Error(). It seems the error message didn't take this unique case into account.
So, the answer is: no, it can't be implemented in Scala, as far as I am aware. But it can't be non-trivially implemented in Java either. And even for trivial implementations, you'd run into the same issues when trying to write code using it.
To make the code work you either have to
Make the FooImpl declaration as abstract class
Implement the bar method
because "Java interfaces don’t implement behaviour".
For your reference see this page.

How to implement Scala apply method in Java

I want to call some Java code from Scala code. I would like to use Scala's apply construct, so I can call it like this:
val led = OutPin(0)
instead of:
val led = new OutPin(0)
I naively implemented an additional apply method in my Java code like this:
public class OutPin {
public OutPin(int pinNumber) {
}
public OutPin apply(int pinNumber) {
return new OutPin(pinNumber);
}
}
This does not make my Scala code (first line above) compile, and instead gives me an error:
Object OutPin is not a value
What is the correct way to implement Scala's apply method in Java?
Your problem is not with the apply method per-se, but with trying to implement a Scala singleton object in Java.
I think (but am not certain) that this is very difficult, perhaps even impossible, by design.
Consider a very, very simple case:
object Obj;
This compiles to two JVM bytcode files, Obj$.class and Obj.class. In theory, it should be easy to just inspect the bytecode of those two classes, and reexpress the same thing in Java. The basic structure of Scala singleton objects is very, very simple:
For a singleton object Obj, a Obj.class and Obj$.class must be generated
The Obj$ class must have a public final static field of type Obj$ called MODULE$, which will be initialized on class initialization refer to the singleton object. In Scala, calls to Obj.foo() get mapped to Obj$.MODULE$.foo() [...if Obj had a method called foo(), that is!]
The Java compiler doesn't know anything about these Scala generated class pairs, so for Java interop, the Obj class contains static functions that just forward to a call of a method of the same name and signature on Obj$.MODULE$.
That sounds complicated, but it's really not so much. It's trivial to write a pair of Java classes that goes this far. But the Scala compiler (2.10.3) still won't recognize the pair as constituting a Scala singleton. Diving into the bytecode of a Scala-compiler generated singleton, you'll see that there are details that are hard to express in legal Java. [Hint: javap -c -p -s -v <fully-qualified-class-name>]
For example, the final static MODULE$ field is initialized indirectly by the static initializer. The static initializer just constructs an Obj$ object, without directly assigning it. The assignment occurs within the private constructor. That's illegal in Java: blank static finals must be certainly initialized in the static initializer, and cannot be assigned in code (like the private constructor) that might potentially be called from outside the initializer and multiple times. The Scala compiler generates bytecode that respects the blank final semantics (because the private constructor is only called once), but exceeds the Java compiler's ability to verify those semantics. So this code would be rejected if expressed in Java.
Also, the Obj class (the version without the terminal dollar sign) includes an annotation of type ScalaSig, which looks quite complicated and would be hard to reproduce by hand (in Java or in Scala), at least for those of us unsure exactly how this annotation works.
I don't know exactly what the Scala compiler looks for before deciding to treat a pair of classes as a "value", that is a valid Scala singleton object, but Scala's designers have chosen not to make it easy, despite the simplicity of the basic scheme. Probably they wish to preserve the ability to reorganize how scala singleton objects translate to bytecode. Letting Java programmers synthesize scala singleton objects would effectively render the current scheme a permanent part of Scala's public API.
Note that writing an ordinary, non-singleton class whose instances have an apply(...) method and so can be called like functions is easy from Java and works fine. Here's a Java cat:
public class Cat {
public String apply( int i ) {
return "Meow: " + i;
}
}
Here's a use of Scala's sugared apply:
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val Morris = new Cat;
Morris: Cat = Cat#6b4feafa
scala> Morris(8)
res0: String = Meow: 8
If you want an apply method that is usable in Scala you should implement it on the scala an side using object to wrap your java class with the same name of the class which instantiate it
object OutPin {
def apply(pinNumber :Int) = new OutPin(pinNumber)
}
The problem is that the Scala compiler says you must define two companion objects in the same file, otherwise you get the error:
Companions 'class OutPin' and 'object OutPin' must be defined in same file
Here is another approach that might work for you. If you define your Scala OutPin in a separate package, then it will work. For example:
Java class:
package base;
public class OutPin {
private final int i;
public OutPin(int i) {
this.i = i;
}
public int getI() {
return this.i;
}
}
Scala class:
package base.scala
object OutPin {
def apply(i: Int): base.OutPin = new base.OutPin(i)
}
Sample Scala client:
import base.scala.OutPin
object Client extends App {
val op = OutPin(1)
println(op.getI)
}
Running Client prints 1
To get access to the sugared apply you would have to import base.scala instead of just base. If it's really important to get the apply syntax it might be worth it.

Categories

Resources