Why 'is' keyword only work with open classes in kotlin? - kotlin

My question might be noob but please help me. I don't understand what is purpose of not allowing non-open classes with "is" keyword in kotlin.
Sample code 1
fun main(){
val randomclassobject = RandomClass()
println(randomclassobject is someRandomInterface)
}
open class RandomClass{
}
interface someRandomInterface{
fun mustImplementThis()
}
The above code works perfectly fine
Now
Sample code 2
fun main(){
val randomclassobject = RandomClass()
println(randomclassobject is someRandomInterface)
}
class RandomClass{
}
interface someRandomInterface{
fun mustImplementThis()
}
without open keyword it shows the error "Error:(3, 34) Kotlin: Incompatible types: someRandomInterface and RandomClass"
Why open keyword really matters?

When you write it like this
class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
It is not possible for any object to be an instance of both RandomClass and SomeRandomInterface because RandomClass itself does not implement SomeRandomInterface and it cannot have any subclasses that implement it either because it is not open (Kotlin classes by default cannot be extended unless you add open).
Since the compiler knows that this check cannot return true, it marks it as an error. Most other languages would probably just warn you that the check is useless, but Kotlin makes it illegal entirely.
On the other hand, when you write
open class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
even though the class itself does not implement the interface, it could have a subclass that implements it, for example
open class RandomClass {
}
interface SomeRandomInterface {
fun mustImplementThis()
}
class RandomSubClass : RandomClass(), SomeRandomInterface {
fun mustImplementThis() {}
}
which means that the check can return true, so the compiler allows it in that case.

Related

Serializer for sealed interface (kotlinx.serialization)

I am trying to serialize my base class that is implementing two sealed interfaces. I have tried multiple approaches, yet i always get the error :
caused by: kotlinx.serialization.SerializationException: Class 'PayloadFromBuilder' is not registered for polymorphic serialization in the scope of 'Payload'.
Mark the base class as 'sealed' or register the serializer explicitly.
I was following mostly this guide Kotlinx/polymorphism and checked some similar questions here.
My code:
sealed inteface MyClass {
dataetc
}
#Serializable
private class DefaultMyClass(dataetc): MyClass
fun MyClass(dataetc): MyClass = DefaultMyClass
Sealed interface MyClassBuilder {
fun dataetc(value: ByteArray)
fun dataetc(value: ByteArray)
fun dataetc(value: ByteArray?)
}
#PublishedApi
#Serializable
#SerialName("payload")
internal class MyClassFromBuilder: MyClassBuilder, MyClass {
}
//Serialization
val module = SerializersModule {
polymorphic(MyClass::class) {
subclass(MyClassFromBuilder::class, MyClassFromBuilder.serializer())
default { MyClassFromBuilder.serializer() }
}
polymorphic(MyClassBuilder::class) {
subclass(MyClassFromBuilder::class, MyClassFromBuilder.serializer())
default { MyClassFromBuilder.serializer() }
}
}
val ConfiguredProtoBuf = ProtoBuf { serializersModule = module }
#ExperimentalSerializationApi
internal inline fun <reified T> ProtoBuf.encodeToMessage(value: T): Message =
Message(encodeToByteArray(value))
From what i have seen i think i am very close to the solution yet i am missing something, since my example is very generic if you need more info let me know, thank you in advance.
Note: In my several tries i have tried to annotate both sealed intefaces with #Polymorphic but i am not sure if it changed anything.
Note 2: My code breaks when i am calling the encodeToMessage fun
So i messed big time, turns out i was not using my ConfiguredProtoBuf when i was calling my encodeToMessage

Why can't you access companion object of reified type parameter?

In the below, since T is reified, I want to use it "almost as if it were a normal class" by accessing its companion object.
class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T> func() {
T.method() // error
}
fun main() {
func<Cls>()
}
But fails with
Type parameter 'T' cannot have or inherit a companion object, so it cannot be on the left hand side of dot
So it seems that a significant amount of information is lost. I get the same error with and without reified. I was hoping a reified type parameter would a fuller generic implementation than Java's. I have a ton of experience in C++ templates.
I've found some workarounds (that are all pretty disappointing using reflection), but really I'm asking why this can't work.
I'm not sure this is answering all the questions, but it's too big for a comment.
First and as stated in the comments, the way the code is written, T is not necessarily a Cls so to allow this you'd need some changes:
open class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T : Cls> func() {
}
open the class and let Kotlin know T is a Cls
However, even though it's inlined, this still wouldn't let you call the companion method because T has no companion. Even without generics:
open class Cls {
companion object {
fun method() { }
}
}
class Foo : Cls
fun main() = Foo.method() // doesn't work
Doesn't work because companions are not inherited. Why? It was a conscious decision by the Kotlin designers. As you know Kotlin aims to correct a lot of issues Java had and this was one.
Static methods in Java are bound at compile-time while overriding is based on dynamic binding at runtime. This becomes quite confusing when you mix both and Kotlin tried to avoid this. Here's an example:
class Cls {
public static void method() {
System.out.println("Cls' method");
}
}
class Foo extends Cls {
public static void method() {
System.out.println("Foo's method");
}
}
public class Main {
public static void main(String[] args) {
Cls parent = new Foo();
parent.method();
}
}
If method would truly be overridden it would print out Foo's method, but indeed this prints Cls' method. The reason is that there's no overriding, but there's shadowing happening. On the other hand, if the methods wouldn't be static, then you'd get Foo's method since it is indeed overridden. This apparently caused confusion amongst developers and Kotlin completely disallowed it.

Implementing multiple overloaded interfaces with `by`

I'd like to leverage by to build class APIs in a nice way. Is there any way to do something like the following?
interface Foo<T> {
fun foo(t: T)
}
inline fun <reified T> createFoo() = object : Foo<T> {
override fun foo(t: T) {
// do stuff
}
}
// This is an error
class StringIntFoo : Foo<String> by createFoo(), Foo<Int> by createFoo()
fun main(){
val foo = StringIntFoo()
foo.foo("")
foo.foo(2)
}
// Doing it manually obviously isn't an issue
class ManualStringIntFoo {
fun foo(t: String){
}
fun foo(t: Int){
}
}
Link to a playground.
It looks like the generated method end up having the same JVM signature. I was hoping the reified types would get around it. With only a single implementation it works just fine and the types look correct.
Is there some way of actually doing this? Whether or not the StringIntFoo is technically a Foo I suppose isn't important for the problem at hand. It would be cool to be able to construct classes in this way.
Doing it manually doesn't work either if you try to actually implement the interfaces: ManualStringIntFoo : Foo<String>, Foo<Int> gives the same error as StringIntFoo.
So by can't help because it still compiles to class StringIntFoo : Foo<String>, Foo<Int> only setting the implementation of methods.

Util class in Kotlin (Best Approach)? [duplicate]

This question already has answers here:
Utils class in Kotlin
(3 answers)
Closed 1 year ago.
I was playing with Kotlin, and creating Util class with different ways. I am approaching a way that works best for calling by either Kotlin or Java.
Now I have created many types of Util. And now I am very confused which is best to use and most important why? I am finding best way considering Heap, Memory, Performance.
My question may look stupid for you guys, but I am in maze and can't come to a solution myself.
Here is my playground.
I have created 5 Kotlin files. in which I have put foo() method. and tried to call by Kotlin and Java.
Calling class Bar.kt
class Bar {
fun bazz() {
UtilClass.instance.foo()
UtilClassObject.UtilClassObject.foo()
UtilCompanionObject.foo()
UtilFileObject.foo()
foo() // from UtilFile
}
}
Calling class Qux.java
public class Qux {
public void bazz() {
UtilClass.Companion.getInstance().foo();
UtilClassObject.UtilClassObject.INSTANCE.foo();
UtilFileKt.foo();
UtilFileObject.INSTANCE.foo();
UtilCompanionObject.Companion.foo();
}
}
And here is the maze that makes me confused to choose best.
UtilClass.kt
class UtilClass {
fun foo() { ... }
companion object {
val instance = UtilClass()
}
}
UtilClassObject.kt
class UtilClassObject {
object UtilClassObject {
fun foo() { ... }
}
}
UtilCompanionObject.kt
class UtilCompanionObject {
companion object {
fun foo() { ... }
}
}
UtilFile.kt
fun foo(){ ... }
UtilFileObject.kt
object UtilFileObject {
fun foo() { ... }
}
It may take to answer my question and explaining it well. So I really appreciate your efforts in advance.
All options are present on the Kotlin reference page for interop between Kotlin and Java: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html
Your options to call from Java something on class MyUtil and call it without an instance such as MyUtil.foo() then you would simply do one of the two options:
// smallest byte code,
// static invocation of foo() from Kotlin side,
// also static call from Java to foo()
object MyUtil {
#JvmStatic fun foo() { ... }
}
or
// creates two classes,
// static lookup of companion followed by virtual call on that instance to foo() from Kotlin,
// Java is a static call to foo()
class MyUtil {
companion object {
#JvmStatic fun foo() { ... }
}
}
And you would call it the same from Kotlin MyUtil.foo(). This is specifically the model of making a Kotlin method static.
Both examples look the same from Java in that they are just direct static calls to a static method. From Kotlin the first example is a static call as well, the second looks up an instance of the companion first and then does a virtual call on the method. The Second example creates two classes, the other only creates a single class.
The other options you present are not more efficient and are uglier syntax. Based on smallest byte code, fewest classes, and fastest performance pick the first example that is 1 class only and all static calls.

Static Instance of Interface as part of the interface

Imagine I had an interface like:
interface MyInterface {
fun doSomething()
}
And I was interop-ing between Kotlin and Java. I now want a constant static instance of this interface but I want that to be part of the interface. I could do this:
interface MyInterface {
fun doSomething()
companion object {
val CONSTANT = object: MyInterface {
override fun doSomething() { ... }
}
}
}
but that means I need to write MyInterface.Companion.getCONSTANT(). #JvmField doesn't work here.
I've also tried:
interface MyInterface {
fun doSomething()
object CONSTANT: MyInterface {
override fun doSomething() { ... }
}
}
}
Which works in other Kotlin files (I can write MyInterface.CONSTANT) but I'd have to write MyInterface.CONSTANT.INSTANCE in Java. This solution seems the closest to what I want.
Any solutions? I want to be able to write MyInterface.CONSTANT in both Kotlin and Java and have them refer to a single static final object that implements the interface.
I believe I could also convert my Interface to an abstract class but that's the last resort.
The issue of not being able to use #JvmStatic in interfaces is tracked in this ticket: https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FKT-6301
It is fixed by now and one comment says
Fix would be avaliable in 1.2.30 under '-language-version 1.3' option