an example where I cannot see a clean solution without SAM convertion for kotlin interfaces:
btw this code is a simplification of a real project. I want to keep the first create function (but we can change the signature of course)
— second edition : pass the function as parameter…
fun main(){
val creator : ?????? = ::c
createStringAndStringBuilder(creator)
}
fun <T:Any> c( clazz: Class<T> ) : T { return clazz.newInstance() }
fun createStringAndStringBuilder(creator:????) {
create<String>(creator)
create<StringBuilder>(creator)
}
inline fun <reified T:Any> create( creator: (Class<T>) -> T ) : T = creator( Class.forName( T::class.java.name ) as Class<T> ) as T
I don’t want to use noeither a java interface nor a object : MyInterface…
fun <T> create(className:String, creator: (Class<T>) -> T ):T =
creator(Class.forName(className) as Class<T>)
fun main() {
val emptyString = create<String>("java.lang.String") { it.newInstance() }
println("the string is empty: its length is ${emptyString.length}")
}
actually no. Creator should not be bound to of create… I want to be able to reuse creator:
let me add a second call to create with same creator:
//i'd like to change the signature to something like
//
// fun <T> create(className:String, <X>(Class<X>) -> X):T
//
// ... but kotlin does not support generics in function parameter...
// using java Function<Class<X>, T> is cheating (it's like admitting we need SAMConvertion... but we don't have it for kotlin... imagine we need 3 input parameters...)
fun <T> create(className:String, creator:Creator):T =
creator.create(Class.forName(className) as Class<T>)
fun main() {
val creator = object:Creator {
override fun <T> create(clazz: Class<T>):T = clazz.newInstance()
}
//i'd like to write : val emptyString = create<String>("java.lang.String") { it.newInstance() }... but no sam convertion
val emptyString = create<String>("java.lang.String", creator)
val emptyStringBuilder = create<StringBuilder>("java.lang.StringBuilder", creator)
println("the string is empty: its length is ${emptyString.length}")
println("the stringBuilder is empty: its length is ${emptyStringBuilder.length}")
}
//i'd like to remove this interface (but kotlin does not support generic function as parameter... So...)
interface Creator {
fun <T> create(clazz: Class<T>):T
}
fun <T:Any> create( className:String, creator: (Class<T>) -> T ) : T = creator( Class.forName( className ) as Class<T> ) as T
create<String>( "java.lang.String" ) { it.newInstance() }
And to reuse creator
fun <T:Any> c( creator: Class<T> ) : T { return creator.newInstance() }
create<String>("java.lang.String" , ::c )
And to avoid the first argument
inline fun <reified T:Any> create( creator: (Class<T>) -> T ) : T = creator( Class.forName( T::class.java.name ) as Class<T> ) as T
create<String>(::c)
so we cannot use a lambda in create call and we need a function reference… This is a big bad point vs java 8+…
this does not really solve my problem because in my real case, ::c is passed in function before been reused… so what is the type of ::c ?
what if I want to stock ::c anywhere ?
example :
fun main(){
val creator : ?????? = ::c
createStringAndStringBuilder(creator)
}
fun <T:Any> c( clazz: Class<T> ) : T { return clazz.newInstance() }
fun createStringAndStringBuilder(creator:????) {
create<String>(creator)
create<StringBuilder>(creator)
}
inline fun <reified T:Any> create( creator: (Class<T>) -> T ) : T = creator( Class.forName( T::class.java.name ) as Class<T> ) as T
You could use creator: (Class<*>) -> Any or maybe this
but then I would lose type safety ({Object()} would be a legal implementation)
your create method does not resolve the problem.
I’ll stick to object : MyInterface { override fun <T> create(x:Class<T>) = x.newInstance() } for now… or creating a java interface to be able to use SAM convertion…
not being able to use a lambda and so being less expressive than java feels bad…
You can get around the lambda limitation by declaring a typealias of a function, instead of a `fun. I think this would work for your case:
typealias Creator<T> = (Class<T>) -> T
fun <T> create(className: String, creator: Creator<T>):T = creator(Class.forName(className) as Class<T>)
fun main() {
val emptyString = create<String>("java.lang.String") { it.newInstance() }
println("the string is empty: its length is ${emptyString.length}")
}
It’s not a creator of t, it’s a creator of *. I don’t want the creator to be limited. I just want the function to be typed. You cannot reuse your creator or you lose type safety.