Remove nullability from generic type parameter - kotlin

Is there a way to remove nullability from generic parameter?
interface Test<A: Any?> {
fun <B> surelyNotNull(): B // must be T for any nullable type T?
}
// usage
val test: Test<String?> = TODO()
test.surelyNotNull() // should return non-nullable String

I'm not really sure what you're trying to achive and how do you want to use this, but how about this?
interface ValidationBuilder<A : Any> {
fun validate(a: A?): A
}
class NotNulLValidator<A : Any> : ValidationBuilder<A> {
override fun validate(a: A?): A {
if (a == null) throw IllegalArgumentException()
return a
}
}

How about specifying a non-nullable generic type in the interface? You would need to mark any null-returning methods accordingly.
interface Test<A : Any> {
fun maybeNull(): A?
fun surelyNotNull(): A
}
val test: Test<String> = TODO()
val notNullable: String = test.surelyNotNull()
val nullable: String? = test.maybeNull()

You can express it as an extension method:
fun <A : Any> ValidatorBuilder<A?>.surelyNotNull(): ValidatorBuilder<A> = TODO()
Though in this case you can't implement it for some ValidatorBuilder differently from another.

Related

why lambda function parameter's type is Nothing on generic type with asterisk in kotlin?

when i call some api, i wished use multiple callback with generic parameter.
so i defined CallBackData class
class CallBackData<T>(val func: (T?) -> Boolean, val params: T?)
it not data class. because it super class of other callbacks.
and i define Array<CallBackData<*>> variable for multiple callback.
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
but when i call func, it say error
Type mismatch.
Required: Nothing?
Found: Any?
i don't get it. why? isn't same it.params type T is same of it.func(param(T))? right? why is Nothing Type? why is not same?
this is full code
fun start(){
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
i tried convert to like this (using out keyword), but it's failed same.(Lambda's parameter type is Nothing?)
fun start(){
val callbackDts : Array<CallBackData<out Any?>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<out Any?>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
i look forward to your reply. thanks!
Unfortunately, the type information of T is gone once you projected a CallbackData<T> to CallbackData<*>. It is no longer known that it.func takes the same type as it.params.
But you do know that they are the same type in the CallBackData class itself, don't you? So you can just add a call method
class CallBackData<T>(val func : (T?) -> Boolean, var params: T?) {
fun call() = func(params)
}
and
callbacks.forEach{
it.call()
}
Or you can overload the invoke operator:
operator fun invoke() = func(params)
You would then be able to do it() directly.
Even if you don't have control over CallBackData, you can still add an extension function:
operator fun <T> CallBackData<T>.invoke() = func(params)
Adding to other answers: if this is the only reason why you defined the CallBackData, then you don't really need this class. Kotlin has support for closures, so we don't need to intercept functions and parameters separately:
fun start(){
val callbackDts = arrayOf<() -> Unit>(
{ sampleCallback1(SomeClass(1)) },
{ sampleCallback2("hello") },
{ sampleCallback3(-1) },
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<() -> Unit>){
callbacks.forEach{
it()
}
}
You can define a function
fun <T> CallBackData<T>.call() = func(params)
and then callApi can be changed to:
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{ it.call() }
}
Then Kotlin does not have a problem to infer that the types of func and params match for each CallBackData.

Ktor reified type parametar

I created class with generic in kotlin and want to use receive with generic, but I have error when i want to call.recieve type from generic:
Can not use MType as reified type parameter. Use a class instead.
Code:
class APIRoute<EType : IntEntity, MType : Any> {
fun Route.apiRoute() {
post {
val m = call.receive<MType>()
call.respond(f(model))
}
}
}
How to fix it?
You need to provide the expected type to the receive() function. Due to type erasure in Java/Kotlin, the type of MType is unknown at runtime, so it can't be used with receive(). You need to capture the type as KType or KClass object when constructing APIRoute.
KClass is easier to use, however it works with raw classes only, it doesn't support parameterized types. Therefore, we can use it to create e.g. APIRoute<*, String>, but not APIRoute<*, List<String>>. KType supports any type, but is a little harder to handle.
Solution with KClass:
fun main() {
val route = APIRoute<IntEntity, String>(String::class)
}
class APIRoute<EType : IntEntity, MType : Any>(
private val mClass: KClass<MType>
) {
fun Route.apiRoute() {
post {
val m = call.receive(mClass)
call.respond(f(model))
}
}
}
Solution with KType:
fun main() {
val route = APIRoute.create<IntEntity, List<String>>()
}
class APIRoute<EType : IntEntity, MType : Any> #PublishedApi internal constructor(
private val mType: KType
) {
companion object {
#OptIn(ExperimentalStdlibApi::class)
inline fun <EType : IntEntity, reified MType : Any> create(): APIRoute<EType, MType> = APIRoute(typeOf<MType>())
}
fun Route.apiRoute() {
post {
val m = call.receive<MType>(mType)
call.respond(f(model))
}
}
}

Map return type from input generic type in Kotlin

I have a function that returns IMyInterface
fun getValue(type: Types): IMyInterface? {}
But I have to always cast the return type in this way before I can use it:
getValue(Types.TypeInt)?.let { value ->
val usableVale = MyInterfaceAsInt.cast(value)
// more code...
}
MyInterfaceAsInt implements IMyInterface and I have no control over them.
The casting always depend of the input, so
Types.TypeInt -> MyInterfaceAsInt.cast(value)
Types.TypeLong -> MyInterfaceAsLong.cast(value)
...etc
Is there a way to define somthing like fun <T = Types> getValue(type: T) in a way that the return type can be inferred from type ?
I would like to do the casting inside getValue.
It looks like Types.TypesInt/Long/etc. are simply instances of the same type Types, not different types; and in fun <T> getValue(type: T), T has to be a type. So it doesn't seem to be possible.
But I would probably go the other way and define functions like
fun getValueAsInt(): MyInterfaceAsInt? = getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
fun getValueAsLong(): MyInterfaceAsLong? = getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
Another alternative which could be useful at least when the type can be inferred:
#Suppress("UNCHECKED_CAST")
inline fun <reified T : MyInterface> getValue(): T? = when(T::class) {
MyInterfaceAsInt::class -> getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
MyInterfaceAsLong::class -> getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
} as T

Kotlin How to create dynamic Object

In javascript we can do something like this
function putritanjungsari(data){
console.log(data.name)
}
let data = {
name:"putri",
div:"m4th"
}
putritanjungsari(data)
In kotlin, i'am creating a function that accept an object as parameter then read it's properties later, how to do that in kotlin that targeting JVM?
If I understood your question correct, you are trying to have a variable that associates keys with some value or undefined(null in kt) if none are found. You are searching for a Map
If you don't know what types you want, you can make a map of type Any? So
Map<String, Any?>
Which is also nullable
Map<String, Any>
If you don't want nullables
Your code for example:
fun putritanjungsari(data: Map<String, Any?>){
print(data["name"])
}
val data: Map<String, Any?> =mapOf(
"name" to "putri",
"div" to "m4th"
)
putritanjungsari(data)
Note that you can't add new keys or edit any data here, the default map is immutable. There is MutableMap (which is implemented the same, only it has a method to put new data)
You can apply the property design pattern to solve your problem.
Here is its implementation in Kotlin:
interface DynamicProperty<T> {
fun cast(value: Any?): T
fun default(): T
companion object {
inline fun <reified T> fromDefaultSupplier(crossinline default: () -> T) =
object : DynamicProperty<T> {
override fun cast(value: Any?): T = value as T
override fun default(): T = default()
}
inline operator fun <reified T> invoke(default: T) = fromDefaultSupplier { default }
inline fun <reified T> required() = fromDefaultSupplier<T> {
throw IllegalStateException("DynamicProperty isn't initialized")
}
inline fun <reified T> nullable() = DynamicProperty<T?>(null)
}
}
operator fun <T> DynamicProperty<T>.invoke(value: T) = DynamicPropertyValue(this, value)
data class DynamicPropertyValue<T>(val property: DynamicProperty<T>, val value: T)
class DynamicObject(vararg properties: DynamicPropertyValue<*>) {
private val properties = HashMap<DynamicProperty<*>, Any?>().apply {
properties.forEach { put(it.property, it.value) }
}
operator fun <T> get(property: DynamicProperty<T>) =
if (properties.containsKey(property)) property.cast(properties[property])
else property.default()
operator fun <T> set(property: DynamicProperty<T>, value: T) = properties.put(property, value)
operator fun <T> DynamicProperty<T>.minus(value: T) = set(this, value)
}
fun dynamicObj(init: DynamicObject.() -> Unit) = DynamicObject().apply(init)
You can define your properties these ways:
val NAME = DynamicProperty.required<String>() // throws exceptions on usage before initialization
val DIV = DynamicProperty.nullable<String>() // has nullable type String?
val IS_ENABLED = DynamicProperty(true) // true by default
Now you can use them:
fun printObjName(obj: DynamicObject) {
println(obj[NAME])
}
val data = dynamicObj {
NAME - "putri"
DIV - "m4th"
}
printObjName(data)
// throws exception because name isn't initialized
printObjName(DynamicObject(DIV("m4th"), IS_ENABLED(false)))
Reasons to use DynamicObject instead of Map<String, Any?>:
Type-safety (NAME - 3 and NAME(true) will not compile)
No casting is required on properties usage
You can define what the program should do when a property isn't initialized
Kotlin is statically typed language, so it required a param type to be precisely defined or unambiguously inferred (Groovy, for instance, addresses the case by at least two ways). But for JS interoperability Kotlin offers dynamic type.
Meanwhile, in your particular case you can type data structure to kt's Map and do not argue with strict typing.
You have to use Any and after that, you have to cast your object, like this
private fun putritanjungsari(data : Any){
if(data is Mydata){
var data = data as? Mydata
data.name
}
}
Just for the sake of inspiration. In Kotlin, you can create ad hoc objects:
val adHoc = object {
var x = 1
var y = 2
}
println(adHoc.x + adHoc.y)

Kotlin - get all properties from primary constructor

I have created this extension method which gets all properties from a KClass<T>
Extension Method
#Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> KClass<T>.getProperties(): Iterable<KProperty1<T, *>> {
return members.filter { it is KProperty1<*, *> }.map { it as KProperty1<T, *> }
}
Example Usage
data class Foo(val bar: Int) {
val baz: String = String.EMPTY
var boo: String? = null
}
val properties = Foo::class.getProperties()
Result
val com.demo.Foo.bar: kotlin.Int
val com.demo.Foo.baz: kotlin.String
var com.demo.Foo.boo: kotlin.String?
How would I modify this extension method to only return properties that are declared in the primary constructor?
Expected Result
val com.demo.Foo.bar: kotlin.Int
You can take constructor parameters by getting primaryConstructor and then valueParameters,
and because primary constructor is not required for kotlin class we can do something like this
inline fun <reified T : Any> KClass<T>.getProperties(): Iterable<KParameter> {
return primaryConstructor?.valueParameters ?: emptyList()
}
so if we will ask for properties of Foo class
val properties = Foo::class.getProperties()
properties.forEach { println(it.toString()) }
we will get
parameter #0 bar of fun <init>(kotlin.Int): your.package.Foo
and the result is not a KProperty, but a KParameter which may be more aligned to your use case
val <T : Any> KClass<T>.constructorProperties
get() =
primaryConstructor?.let { ctor ->
declaredMemberProperties.filter { prop ->
ctor.parameters.any { param ->
param.name == prop.name
&&
param.type == prop.returnType
}
}
} ?: emptyList()
fun <T : Any> KClass<T>.getProperties(): Iterable<KProperty1<T, *>> =
constructorProperties
This is a rework of previous answers by szymon_prz and Peter Henry, to produce the list of properties declared in the primary constructor, but not:
other primary constructor parameters that are not properties
other properties that are not primary constructor parameters but have matching names and different types
Unfortunately it will still list properties that are not primary constructor parameters but have the same name and type as one of them.
For example:
// only parameter 'bar' is declared as a property
class Foo(val bar: Int, baz: Int, qux: Int, rod: Int) {
val zzz = baz // no parameter zzz
val qux = "##($qux)##" // property is a String but parameter is an Int
val rod = maxOf(0, rod) // property and parameter are both Int
}
val ctorProps = Foo::class.constructorProperties
ctorProps.forEach { println(it.toString()) }
will produce:
val Foo.bar: kotlin.Int
val Foo.rod: kotlin.Int
inline fun <reified T : Any> KClass<T>.getProperties(): List<KProperty<*>> {
val primaryConstructor = primaryConstructor ?: return emptyList()
// Get the primary constructor of the class ^
return declaredMemberProperties.filter {
// Get the declared properties of the class; i.e. bar, baz, boo
primaryConstructor.parameters.any { p -> it.name == p.name }
// Filter it so there are only class-properties whch are also found in the primary constructor.
}
}
To summarize, this function basically takes all the properties found in a class and filters them so only ones that are also found in the primary-constructor stay.