Is there a way to cast from 'String' to 'KType'? - kotlin

Simply, I want a function like:
fun <T> convert(val foo: String, fooT: KType) : T {
...?
}
For Int, it would return foo.toInt(), for Double, foo.toDouble(), and to some unknown type, just throw an exception. I think it's not so hard to create my own switch statement for the types I expect, but out of curiosity - is there a way already?

Recommended way
Unfortunately, there's no easy generic way because we're not dealing with casts, but method calls. This would be my approach:
fun <T> convert(str: String, type: KType) : T {
val result: Any = when (type.jvmErasure)
{
Long::class -> str.toLong()
Int::class -> str.toInt()
Short::class -> str.toShort()
Byte::class -> str.toByte()
...
else -> throw IllegalArgumentException("'$str' cannot be converted to $type")
}
return result as T // unchecked cast, but we know better than compiler
}
Usage:
#UseExperimental(ExperimentalStdlibApi::class)
fun main() {
val int = convert<Int>("32", typeOf<Int>())
println("converted: $int")
}
Instead of a KType parameter, you could also use a Class<T> and make the function reified, so it can be called as convert<Int>("32") or even "32".toGeneric<Int>().
Hardcore way
While there is no easy way, it is possible to access the type using heavy reflection and relying on implementation details. For this, we can extract the type name from the KType object, find an extension method (in a different class) that matches, and call it using reflection.
We have to use to*OrNull() instead of to*(), because the latter is inline and won't be found by reflection. Also, we need to resort to Java reflection -- at this time, Kotlin reflection throws UnsupportedOperationException for the types involved.
I do not recommend this in productive code, as it's inefficient and can break with future standard library versions, but it's a nice experiment:
fun convert(str: String, type: KType): Any {
val conversionClass = Class.forName("kotlin.text.StringsKt")
// here, the to*OrNull() methods are stored
// we effectively look for static method StringsKt.to*OrNull(String)
val typeName = type.jvmErasure.simpleName
val funcName = "to${typeName}OrNull" // those are not inline
val func = try {
conversionClass.getMethod(funcName, String::class.java) // Java lookup
} catch (e: NoSuchMethodException) {
throw IllegalArgumentException("Type $type is not a valid string conversion target")
}
func.isAccessible = true // make sure we can call it
return func.invoke(null, str) // call it (null -> static method)
?: throw IllegalArgumentException("'$str' cannot be parsed to type $type")
}

Related

How to overload function with different return types and the same parameters in Kotlin?

I want to overload function with the same parameters (or without parameters at all) and different return types. Correct implementation should be chosen by the type of variable I assign returning value of a function to.
The only way to do this I found is using reified generics and comparing KClass'es:
inline fun <reified T: Any> read(): T {
return read(T::class)
}
#Suppress("UNCHECKED_CAST")
fun <T: Any> read(t: KClass<T>): T {
return when (t) {
Int::class -> readInt() as T
UInt::class -> readUInt() as T
String::class -> readString() as T
// ...
else -> throw Exception("Unsupported type")
}
}
fun readInt(): Int {
// ...
}
fun readUInt(): UInt {
// ...
}
fun readString(): String {
// ...
}
The problem with this approach is that the compiler and IDEA are not smart enough to determine types at compile time for which there is no implementation. The most I can do is throw a runtime exception:
val int: Int = read()
val string: String = read()
val double: Double = read()
// ^^^^ No compile-time error here
Maybe I'm missing something and there is more "correct" way of doing this?
Maybe I'm missing something and there is more "correct" way of doing this?
No. You cannot do this at all. You must name the methods differently.

Kotlin custom Scope function return type not behaving as expected

this custom function call's a lambda block when null.
I expected the function definition below to enforce the same return type. : T
Is their a way to enforce that be block returns type T ?
inline fun <T> T?.whenNull(block: () -> T): T {
if (this == null) {
return block() //accepts any return type
} else {
return this
}
}
fun main() {
val x : Int? = null
println(x ?: 42)
println(x.whenNull { 42 })
println(x.whenNull { "why is kotlin not enforcing return of the same type?" })
}
T in the second whenAll call is being inferred as Any. Imagine that all occurrences of T are replaced Any, the call would be valid, wouldn't you agree? Int and String are both subtypes of Any, after all.
inline fun Any?.whenNull(block: () -> Any): Any {
if (this == null) {
return block()
} else {
return this
}
}
fun main() {
println(x.whenNull { "why is kotlin not enforcing return of the same type?" })
}
Basically, the Kotlin compiler is "trying too hard" here to make your code compile, and infers an unexpected type for your type parameter.
There exists an internal annotation #kotlin.internal.InputTypesOnly that would prevent your code from compiling if the type inferred is not mentioned in one of the input types (parameter types, receiver type, etc) of the function.
In this case, the input type is just Int?, and T is inferred to be Any, so it would be make your code not compile as expected. Unfortunately though, this annotation is internal, and you cannot use it :( KT-13198 is the ticket about making it public.
Interestingly, when passing this to the block the type is preserved and works as expected.
inline fun <T> T?.whenNullAlt(block: (T?) -> T): T {
if (this == null) {
return block(this) // "this" is superfluous, but enforces same return type
} else {
return this
}
}
fun main() {
val x : Int? = null
println(x.whenNullAlt { 42 })
println(x.whenNullAlt { "does not compile" })
}
As other answers pointed out, this is technically correct from Kotlin viewpoint because it can infer T to Any and it would compile.
However, while technically correct, this is a known problem in Kotlin language and is going to be fixed some day. That noted, let's try to understand why your answers's code works while your questions' doesn't.
The reason for this is that lambdas are always inferred last: imagine it as being a queue on what parts of the expression need to have their types inferred and anything inside a lambda is always at the end of the queue, no matter where the lambda is in the expression. So, when going over your example, it infers everything else, decides that the type of this should be Int?, than goes to the lambda, sees a String return type and merges them into Any being very proud of itself.
In the other example, however, the lambda is passed an external fact about it's parameter — the already inferred Int from the receiver (lambda is always the last to get the info, remember?). That way the inference inside the lambda fails because the argument and the result type are in disagreement.

Kotlin generic factories

I'm trying to create an AnimalFactory that returns generic factories for making different types of Animals, depending on the arguments passed to the AnimalFactory.
Here's the code:
interface Animal {
fun talk(): String
}
class Cow: Animal {
override fun talk(): String {
return "mooo"
}
}
class Cat: Animal {
override fun talk(): String {
return "miow"
}
}
class Dog: Animal {
override fun talk(): String {
return "bark"
}
}
object AnimalFactory {
fun <T: Animal> AnimalMakerFactory(type: String): AnimalMaker<T> {
val maker = when (type) {
"cat" -> CatMaker()
"dog" -> DogMaker()
else -> CowMaker()
}
return maker
}
}
interface AnimalMaker<out T: Animal> {
fun make(): T
}
class CatMaker: AnimalMaker<Cat> {
override fun make(): Cat {
return Cat()
}
}
class DogMaker: AnimalMaker<Dog> {
override fun make(): Dog {
return Dog()
}
}
class CowMaker: AnimalMaker<Cow> {
override fun make(): Cow {
return Cow()
}
}
I get a type exception:
Type mismatch.
Required: AnimalMaker<T>
Found: AnimalMaker<Animal>
I thought that AnimalMaker would solve this, but apparently not. Why is AnimalMaker<T> not of type AnimalMaker<Animal> here?
The return value of the function is AnimalMaker<T> and not AnimalMaker<Animal> because that’s what you declared as the return type. The variable maker is indeed an AnimalMaker<Animal> but that isn’t a match for what the function is supposed to return because T could be a subtype of Animal.
You declared your function as having a generic type of T: Animal. Generic types are always an input to the function. In this case, it doesn’t make sense to use a generic input to the function because there’s no way to enforce that the type given is a match for the input String it corresponds with. To make your function work, you can remove <T : Animal and declare that it returns AnimalMaker<Animal>.
A little more explanation. There are two reasons why you might want to use generics in a function signature.
Enforce input parameter types.
Determine the output type.
You might use generics for one or both reasons (but the second can only be done by itself in a useful way by using reified generics, except in very specific cases where the returned class won’t be producing anything).
In your case, your input generic is not used to enforce the input parameter since that is just a String. To use it for the second reason, you would have to cast your return value’s type to the unknown (to the compiler) type T which would be unsafe because there’s no way to know if the input type given at the call site is a valid match for the given input String. And if you expected the call site to pass the right type, it would be redundant and error prone to also require a matching String to be passed.
Edit:
If you know the input type at compile time, then you can do this with reified generics. Get rid of the String input. It would look like this:
object AnimalFactory {
inline fun <reified T: Animal> AnimalMakerFactory(): AnimalMaker<T> {
#Suppress("UNCHECKED_CAST")
return when (T::class) {
Cat::class -> CatMaker()
Dog::class -> DogMaker()
Cow::class -> CowMaker()
else -> error("No factory found for type ${T::class}.")
} as AnimalMaker<T>
}
}
// Example usage
val someCatFactory = AnimalFactory.AnimalFactoryMaker<Cat>()
val cat: Cat = someCatFactory.make()
Inside this function, it is up to you to match the types up correctly, or there will be a ClassCastException at runtime. It seems logically it should be able to automatically cast them, but the compiler isn't sophisticated enough (yet?).

Kotlin - when expression over class type

I'm attempting to write an invocation handler that uses a map (supplied at runtime) to implement an interface's getters.
This very crudely works. I know the basic types that may be returned, so I'm OK with having a when expression.
I haven't found a way to avoid using the name of the class as the subject of the when expression; is there a better way?
class DynamicInvocationHandler<T>(private val delegate: Map<String, Any>, clzz: Class<T>) : InvocationHandler {
val introspector = Introspector.getBeanInfo(clzz)
val getters = introspector.propertyDescriptors.map { it.readMethod }
override fun invoke(proxy: Any, method: Method, args: Array<Any>?): Any? {
if (method in getters) {
// get the value from the map
val representation = delegate[method.name.substring(3).toLowerCase()]
// TODO need better than name
when (method.returnType.kotlin.simpleName) {
LocalDate::class.simpleName -> {
val result = representation as ArrayList<Int>
return LocalDate.of(result[0], result[1], result[2])
}
// TODO a few other basic types like LocalDateTime
// primitives come as they are
else -> return representation
}
}
return null
}
}
You can use the types instead of the class names in the when statement. After a type is matched, Kotlin smart cast will automatically cast it
Example
val temporal: Any? = LocalDateTime.now()
when (temporal){
is LocalDate -> println("dayOfMonth: ${temporal.dayOfMonth}")
is LocalTime -> println("second: ${temporal.second}")
is LocalDateTime -> println("dayOfMonth: ${temporal.dayOfMonth}, second: ${temporal.second}")
}
when expressions support any type (unlike Java's switch), so you can just use the KClass instance itself:
when (method.returnType.kotlin) {
LocalDate::class -> {
...
}
...
}

Kotlin: store any type of function reference in a variable

Is it possible to have a variable that can holds any type function.
Like :
fun method1(par: Boolean){}
fun method2(par: Boolean) : Int{return 1}
fun method3(par: Boolean, par2: Boolean) : Int{return 1}
var funtionHolder : ((Any)->Any) ?= null //What should I write here?? so to hold any type of function
fun method4(){
.........
funtionHolder = ::method1 //getting compile time error
.........
funtionHolder = ::method2 //getting compile time error
.........
funtionHolder = ::method3 //getting compile time error
}
After holding the function_reference I need to invoke it later. So I need to holds it parameter type and state also.
You can hold them in a KFunction<Any> or its superclass KCallable<Any> because you know nothing about the parameter list and nothing about the return type, so you have to go to something that can reference at that level of abstraction. These instances can then be invoked more generically using the call() or callBy() methods. (this requires the kotlin-reflect dependency). To do something safer and to call like a normal function you'd have to cast back to the specific function type later.
If you want to avoid this, you'll need to unify your signatures to something you can point to with another function type (i.e. KFunction1 or KFunction2). Otherwise how you'll call this, what you'll do with it will be up to you at this point because you erased all the information that allows you to easily call the function.
val functionHolder1: KFunction<Any> = ::method1 // success!
val functionHolder2: KFunction<Any> = ::method2 // success!
val functionHolder3: KFunction<Any> = ::method3 // success!
You can then make a DeferredFunction class to hold these along with parameters you want to later pass, and then invoke it whenever in the future.
class DeferredFunction(val function: KFunction<Any>, vararg val params: Any?) {
#Suppress("UNCHECKED_CAST")
operator fun <T> invoke(): T {
return function.call(params) as T
}
}
fun whatever(name: String, age: Int): String {
return "$name of age $age"
}
val functionHolder = DeferredFunction(::whatever, "Fred", 65)
println(functionHolder<String>()) // "Fred of age 65"
You do not need the generic return type on the invoke function and could just make it return Any or call it as functionHolder<Any>() but it is nice if you know what to expect for the return. You can decide what to do there based on your actual use case. Also no need to special case for no parameters, just don't pass any, i.e. DeferredFunction(::otherFunc)
With reference from Jayson's answer, added extra code to hold the state of the function by using vararg and spread operator(*).
var functionHolder: KFunction<Any> ?= null
var paramsHolder : Array<out Any?> ?= null
fun hold(functionReference : KFunction<Any>, vararg args : Any?) {
this.functionHolder = functionReference
this.paramsHolder = args
}
fun release() {
if (functionHolder != null) {
if (paramsHolder != null) {
functionHolder?.call(*paramsHolder!!)
} else {
functionHolder?.call()
}
}
}
......
fun method3(par: Boolean, par2: Boolean) : Int{return 1}
......
hold(::method3, true, false)
release()//it works
No. Kotlin is static typed language and doesn't allow this. Else what happens when this is called?
functionHolder->invoke(3)
and when functionHolder is assigned a lamda that doesn't take parameter?