4

I have this code:

package org.medianik.kotlindoc

fun main(){
    val creator:Creatable = toCreatable(::Created)// Ok. Compiles, and works fine
    val creator1:Creatable = ::Created // Compilation error
    val creator2:Creatable = ::Created as Creatable // ok enough to compile, but there is runtime exception
    val c = creator.create(5)
    val creator3:Creatable = toCreatable(c::doSmth1) // Ok. Compiles, works fine
    val creator4:Creatable = c::doSmth1 // Compilation error
    val creator5:Creatable = c::doSmth1 as Creatable // Again ok enough to compile, but there is runtime exception
    val creator6:Creatable = Creatable { i -> Created(i) } // Works fine, but that's not what I want
}

fun toCreatable(c:Creatable) = c

fun interface Creatable{
    fun create(i: Int) : Created
}
class Created(private var i: Int){
    fun doSmth1(add: Int): Created{
        return this.also { i+=add }
    }
}

Exception for creator2:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator2$1 cannot be cast to class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator2$1 and org.medianik.kotlindoc.Creatable are in unnamed module of loader 'app')

Exception for creator5:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator5$1 cannot be cast to class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator5$1 and org.medianik.kotlindoc.Creatable are in unnamed module of loader 'app')

I have no idea how to make creator1/4 work with method reference. Is there any ways to make them work? Because it seems senseless to me: if you pass method reference to a function as an argument -- it converts to interface, otherwise not. How does it work?

Are there some special casts for functions to interfaces?

MediaNik Ok
  • 121
  • 5

1 Answers1

0

I copied your code into IntelliJ and also got errors in the lines

 val creator:Creatable = toCreatable(::Created)
 val creator3:Creatable = toCreatable(c::doSmth1)

The issue is, that Creatable is a named Interface that has the same Method signature like the class Created but this class does not implement the interface.

Note, a function does not implement an interface, even if they have a signature.

You could decare instead of an interface a function type. Note, this is not the same, but they can be handled almost the same.

typealias Creatable = (Int) -> Created

or you could write write a wrapper acceping such function type:

fun toCreatable(c:(Int) -> Created) = object: Creatable {
    override fun create(i: Int): Created {
        return c(i)
    }
}

this function accepts an function and returns an object that actually implements the interface.

Jens Baitinger
  • 2,230
  • 14
  • 34
  • Yes, I know about typealias. As said at kotlinlang.org: Functional interfaces vs. type aliases Functional interfaces and type aliases serve different purposes. Type aliases are just names for existing types – they don't create a new type, while functional interfaces do. Type aliases can have only one member, while functional interfaces can have multiple non-abstract members and one abstract member. Functional interfaces can also implement and extend other interfaces. Considering the above, functional interfaces are more flexible and provide more capabilities than type aliases. – MediaNik Ok Apr 03 '21 at 12:39
  • So I wanted to know if there is short way to use interface in lambda context(as if it were typealias). – MediaNik Ok Apr 03 '21 at 12:42