About type parameter of generic in Kotlin - kotlin

I'm studying kotlin language and I can't distinguish these examples, especially nullable types in a 'where' clause of generic.
Would you tell me the difference?
case 1
class Foo<T> where T: Comparable<T>
class Foo<T> where T: Comparable<T?>
class Foo<T> where T: Comparable<T>?
class Foo<T> where T: Comparable<T?>?
case 2
class Foo<T> where T: Comparable<T>? {
// If a class is declared like above, is a type 'T' already nullable?
// Then,
fun bar(value: T?) { // Should I declare a member function like this to accept null or
// do something
}
fun bar(value: T) { // Should I declare like this instead?
}
}

First, to distinguish T : Comparable<T> and T : Comparable<T?>, take a look at the following example. The difference is whether you can compare T with T?.
class Bar1(var bar : Int) : Comparable<Bar1>{
override fun compareTo(other : Bar1) : Int {
return bar - other.bar
}
}
class Bar2(var bar : Int) : Comparable<Bar2?>{
override fun compareTo(other : Bar2?) : Int {
return bar - ( other?.bar ?: 0 )
}
}
fun main(){
println(Bar1(1) > Bar1(2))
val bar2 : Bar2? = Bar2(2)
println(Bar2(1) > bar2)
}
Output:
false
false
The difference is that
val bar1 : Bar1? = Bar1(2)
println(Bar1(1) > bar1)
will not compile. bar1 must be unwrapped
Second, to distinguish class Foo<T> where T: Comparable<T>? and class Foo<T> where T: Comparable<T>?, it has nothing to do with comparable. Take a look at the following simplified example.
class Foo1<T>(val t : T) where T : Int{
override fun toString() : String{
return "$t"
}
}
class Foo2<T>(val t : T) where T : Int?{
override fun toString() : String{
return "$t"
}
}
fun main(){
println(Foo1(5))
val i : Int? = 5
println(Foo2(i))
}
Output:
5
5
The difference is that println(Foo1(i)) will not compile. i must be unwrapped.

Related

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))
}
}
}

Type inference of class type parameter in abstract method

// Bars.kt
abstract class Bar
class BarToo(/* fields */) : Bar()
// Foos.kt
abstract class Foo<T : Bar> {
abstract fun foo(bar: T)
}
class FooToo : Foo<BarToo>() {
override fun foo(bar: BarToo) { /* */ }
}
// FoosBars.kt
private val foos = HashMap<String, Foo<out Bar>>()
fun <T : Foo<out Bar>> putFoo(name: String, foo: T) {
foos.putIfAbsent(name, foo)
}
fun doFoo(name: String, bar: Bar) {
val foo = foos[name] ?: return
// Error: Type mismatch: inferred type is Bar but Nothing was expected
// https://pl.kotl.in/TSp3eO_Tj
foo.foo(bar)
}
If I manually specify the bounds of T at the method's declaration, the error in doFoo is resolved, e.g.:
abstract class Foo /* ... */ {
abstract <T : Bar> fun foo(bar: T)
}
but obviously prevents the subclasses from using the type parameter from the class declaration.
Is this type of hierarchy possible in Kotlin, or should I better explain what I am trying to accomplish in order to avoid an XY problem?
Thanks!
You need to use in instead of out. This allows child classes to be used as follows:
foo.foo(bar)
foo.foo(BarToo()) // no compile error
Ref: this

Is there a way to make sealed classes generics?

How a generic result or error type could be defined in Kotlin? Something like this example from TypeScript
type Errorneous<E, R> =
{ is_error: true, error: E } | { is_error: false, result: R }
function calculate(): Errorneous<String, Number> {
return { is_error: false, result: 2 }
}
The problem is that Kotlin doesn't have generic sealed classes.
It's possible to define something like
data class Errorneous<E, R>(val error: E?, val result: R?)
But it not ideal as it allows wrong usage like
Errorneous<String, Int>(null, null)
Errorneous<String, Int>("", 2)
UPDATE
Possible (not compiling) Kotlin code
sealed class Errorneous
class Success<R>(val result: R) : Errorneous()
class Fail<R>(val error: R) : Errorneous()
fun calculate(): Errorneous {
return Success(2)
}
fun main() {
val result = calculate()
if (result is Success<*>) {
val r: Int = result.result // <= Problem here, no smart cast
}
}
You have to add generic parameters to the base class as well:
sealed class Errorneous<E,R>
class Error<E,R>(val error: E): Errorneous<E,R>()
class Success<E,R>(val result: R): Errorneous<E,R>()
fun calculate(): Errorneous<String, Int> {
return Success(2)
}
fun main() {
val result = calculate()
if (result is Success<*, Int>) {
val r: Int = result.result // <= smart cast
}
}

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.

How to get around Type mismatch Required: Foo<Type>, Found: Foo<Type?>

Given the following Kotlin code:
class Foo<T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
Why do I get the following error:
Type mismatch. Required: Foo<String?> Found: Foo<String>
If I remove the ? from the extension function to be Foo<T>.transform I instead get the following error:
Type mismatch. Required: Foo<Int> Found: Foo<Int?>
I can understand the second error, because you cannot assign Int? to Int, but the first doesn't make any sense, as you can assign String to String?
EDIT:
I have modified the class Foo<T> to be class Foo<out T> and this works for me as the value t will only ever be read after the initial assignment. With this option I do not need to define the type parameters at the call site of transform.
Another option I have found that I think is a bit messy (and not sure why it makes a difference) is adding a third type parameter to the extension function as follows:
fun <T : Any, U : T?, R : Any> Foo<U>.transform(transformer : (T) -> R) : Foo<R?>
The call site of this on the other hand I find a bit odd. Looking at the above code the call of foo.transform MUST NOT include the type parameters, but the call of bar.transform<Int, Int?, IntRange> MUST include the type parameters in order to work.
This option allows setting the value t at some later point if it were a var instead of val. But it also removes the smart casting on t in the transform function. Although that can be gotten around with a !! if you are not worried about race conditions or (with some additional effort) ?: or ?. if you are worried about race conditions.
You can change your Foo<T> class to be not invariant (see https://kotlinlang.org/docs/reference/generics.html):
class Foo<out T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
The out T specifies precisely the behavior you want.
Since you specify the property t in the constructor as T? you don't need to specify Foo<T?> as receiver and Foo<R?> as return type. Instead use Foo<T> and Foo<R> and it will work.
class Foo<T>(val t : T?)
fun <T: Any, R: Any> Foo<T>.transform(transformer : (T) -> R) : Foo<R> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform { t -> t.length }
val baz = bar.transform { t -> t..(t + 1) }
}
Note: You don't need to specify the generic types for transform because they can be inferred (at least in this example).