Would it be possible to make the compiler process ...
# compiler
t
Would it be possible to make the compiler process this pattern without writing overloads for
someFun
?
Copy code
fun someFun( aRef : AFunction<String> ) { }

fun otherFun() {

    someFun { /* code */ }
    someFun(::anotherFun)
    someFun("fragment-key")
    someFun(fragmentResourceSet)

}
Explanation in thread.
My framework lets the programmer instantiate UI components different ways: 1. hard coded (lambda or Kotlin function reference) 2. a key that is used to look up the component in a registry 3. a resource that can be used to load the component from a remote source (i.e. over the network) It would be great to be able to use these in a similar way without writing all the overloads. The idea is that the compiler plugin would check what is passed to the function (report an error if unacceptable) and convert it into an
AFunction
. The type parameters of
AFunction
would be the parameters of the called function, similar to
KFunction
(but without the return type). I think I can write the IR part easily but I don't know if it is possible to do this somehow in FIR so it won't show an error. Maybe generating the necessary overloads in FIR and simply removing them in IR?
y
Copy code
interface AFunction<T> {
    
}
fun interface AFunctionConsumer<T> {
    operator fun invoke(f: AFunction<T>)
}
operator fun <T> AFunctionConsumer<T>.invoke(f: (T) -> Unit): Unit = TODO()
operator fun AFunctionConsumer<*>.invoke(regKey: String): Unit = TODO()
operator fun AFunctionConsumer<*>.invoke(res: Int): Unit = TODO()

val someFun: AFunctionConsumer<String> = AFunctionConsumer {  }
fun anotherFun(x: String) {}
val fragmentResourceSet = 42
fun otherFun() {

    someFun { /* code */ }
    someFun(::anotherFun)
    someFun("fragment-key")
    someFun(fragmentResourceSet)

}
thank you color 1
t
Thank you for this idea. However, I would like to stick to the
fun someFun( ...)
style declaration because of two reasons: • I need more then one parameter • this is a library where this pattern is quite frequently used, the
val
style declaration of functions seems a bit confusing • I would have to need to modify the compiler plugin anyway to handle this pattern
Your idea gave me another idea which seems to be acceptable. The
fromKey
and
fromResource
function calls will be replaced by the compiler plugin. The only downside is that you have to specify the parameter types, but those are in most cases zero, and very rarely more than one.
Copy code
fun someFun0(i1 : Int, block : () -> Any) {  }
fun someFun1(i1 : Int, block : (i2 : Int) -> Any) {  }

fun fromKey(key : String) : Function0<Any> = replacedByPlugin("")
fun <P1> fromKey(key : String) : Function1<P1,Any> = replacedByPlugin("")

fun fromResource(resource : FileResourceSet) : Function0<Any> = replacedByPlugin("")
fun <P1> fromResource(resource : FileResourceSet) : Function1<P1,Any> = replacedByPlugin("")

fun anotherFun0() {  }
fun anotherFun1(i2 : Int) {  }

fun otherFun() {
    someFun0(12) {  }
    someFun0(23, ::anotherFun0)
    someFun0(34, fromKey("key"))
    someFun0(45, fromResource(Files.a))

    someFun1(12) {  }
    someFun1(23, ::anotherFun1)
    someFun1(34, fromKey<Int>("key"))
    someFun1(45, fromResource<Int>(Files.a))
}
d
Answering the original question: it's partially possible. Eventually what you want here are type conversions (e.g. from
String
to
AFunction<String>
). There are no custom conversions in the language, but there are some builtin ones, like •
() -> Unit
->
suspend () -> Unit
(Int) -> String
->
fun interface FromIntToString
(any kind of SAM-conversion) •
operators on Int literals
->
Long
(
takeLong(1 + 1)
,
1 + 1
has
Int
type)
thank you color 1