Is the Kotlin documentation correct? - kotlin

Is the code (show below) correct? It was take from page 63 of the Kotlin-docs.pdf, which is also the last code snippet of https://kotlinlang.org/docs/reference/generics.html
fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>
where T : Comparable, T : Cloneable {
return list.filter { it > threshold }.map { it.clone() }
}
Taken by as is, the compiler fails with:
1. One type argument expected for interface Comparable defined in kotlin
2. Type inference failed. Expected type mismatch: inferred type is List but List was expected
3. Cannot access 'clone': it is protected in 'Cloneable'
The first two errors are easily resolved by changing the code to the following:
fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<Any>
where T : Comparable<in T>, T : Cloneable {
return list.filter { it > threshold }.map { it.clone() }
}
I still get the following error:
Cannot access 'clone': it is protected in 'Cloneable'
I'm using Kotlin 1.1.2-release-IJ2017.1-1
Am I missing something? or is there an error in the documentation?
Thanks.

it.clone() returns Any and you get error casting List to List.
So, you have changed it to List.
Your next error is Cannot access clone: it is protected in Cloneable.
This problem can be solved by creating our own Cloneable interface with public method.

Related

Why is this Kotlin class property not shadowed by a method parameter?

Looking at this code in kotlinx.coroutines, I noticed something strange:
/**
* Returns a flow containing the results of applying the given [transform] function to each value of the original flow.
*/
public inline fun <T, R> Flow<T>.map(crossinline transform: suspend (value: T) -> R): Flow<R> = transform { value ->
return#transform emit(transform(value))
}
In the first line, the transform used is clearly this.transform (defined here). Shouldn't the transform declared in the method parameter have been used instead, as it is in the second line?
To test this, I wrote a small class which tries to mimc this behaviour:
// flow.kt
class Flow(val name: String) {
public fun transform (transform: (Any) -> Unit): Flow {
return Flow("transformed")
}
public fun emit(value: Any) {
// do nothing
}
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
return#transform(emit(transform(value)))
}
}
And I get the kind of warning I was expecting when I run kotlinc flow.kt:
flow.kt:12:54: error: type mismatch: inferred type is Unit but Flow was expected
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
^
flow.kt:12:66: error: cannot infer a type for this parameter. Please specify it explicitly.
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
^
(Kotlin version as returned by kotlinc -version is "kotlinc-jvm 1.6.10 (JRE 17.0.1+1)")
So why is it that the code defined in kotlinx.coroutines works? If I understand Kotlin's name shadowing rules correctly it shouldn't have.
In kotlinx.couroutines, the transform parameter takes an argument of type T. Hence, this.transform is used when transform is called with a (Any) -> Unit argument.
In your example, the transform parameter takes an argument of type Any. A (Any) -> Unit is an Any and hence the parameter is being used instead of this.transform. Replacing Any with a type parameter will make your code compile too.

Cast reified generic type as non-null with Any upper bound

I’m trying to use a reified type parameter to check if the type argument is nullable, returning a different class implementation based on the nullability of the type argument. This works well, except for the non-null subclass requiring its generic type to have a non-null Any upper bound, in order to have a KClass<T> constructor argument.
This code works as expected:
interface Test
class NullableT<T> : Test
class NonNullT<T> : Test
inline fun <reified T> test(): Test {
return if (null is T) {
NullableT<T>()
} else {
NonNullT<T>()
}
}
test<String?>()::class.simpleName // NullableT
test<String>()::class.simpleName // NonNullT
However, this code has a compiler error:
interface Test
class NullableT<T> : Test
class NonNullT<T : Any>(tClass: KClass<T>) : Test
inline fun <reified T> test(): Test {
return if (null is T) {
NullableT<T>()
} else {
NonNullT<T>(T::class) // <-- error with <T>
// Type argument is not within its bounds. Expected: Any Found: T
}
}
Following the check for !(null is T), there needs to be some way to cast T as having a non-null Any upper bound.
It’s possible to make a non-null T optional. This works:
interface Test
class NullableT<T> : Test
class NonNullT<T : Any> : Test
inline fun <reified T : Any> test(nullable: Boolean): Test {
return if (nullable) {
NullableT<T?>()
} else {
NonNullT<T>()
}
}
test<String>(true)::class.simpleName // NullableT
test<String>(false)::class.simpleName // NonNullT
But I need a way to make a nullable T non-null. This isn’t valid:
interface Test
class NullableT<T> : Test
class NonNullT<T : Any> : Test
inline fun <reified T> test(nullable: Boolean): Test {
return if (nullable) {
NullableT<T>()
} else {
NonNullT<T!!>() // Type parameter 'T' is not an expression
}
}
This works:
import kotlin.reflect.*
interface Test
class NullableT<T> : Test
class NonNullT<T : Any>(tClass: KClass<T>) : Test
inline fun <reified T> test(dummy: Nothing? = null): Test {
return NullableT<T>()
}
inline fun <reified T: Any> test(): Test {
return NonNullT<T>(T::class)
}
fun main(){
println(test<Any>().toString())
println(test<Any?>().toString())
println(test<String>().toString())
println(test<String?>().toString())
}
"But why does this work?" I hear you asking. Well simply, what's happening here is that the Kotlin compiler prefers functions that match the number of passed in parameters (in this case 0) over functions that have default parameters that would result in allowing the number of passed in parameters (in other words, if you call a function with 1 argument, the compiler will prefer a function with 1 parameter over a function with 2 parameters where the 2nd parameter has a default value). However, because T has a different upper bound in the 2 functions, if the type that you're trying to invoke test with doesn't follow the upper bound of the preferred function (which in this case is the one that returns NonNullT), the compiler will fall back to calling the more broad test function (i.e. the one that returns NullableT).
This solution is kinda hacky, but sadly I don’t think there’s any other way to implement it.
No, you can't add dynamic type bound to type parameter since it can be checked only at compile-time because of type erasure.
Kotlin Nullability feature doesn't exist at compile-time too.

Kotlin generic interface resolver

I'm trying to build a resolver that given some domain context return back an implementation of a generic interface. The code is the following (domain abstracted):
interface Interface<T>
class StringImplementation: Interface<String>
class BooleanImplementation: Interface<Boolean>
class Resolver {
fun <T : Any> resolve(implementation: String): Interface<T> {
return when (implementation) {
"string" -> StringImplementation()
"boolean" -> BooleanImplementation()
else -> throw IllegalArgumentException()
}
}
}
This snippet looks good to me but the compiler is complaining because Type missmatch: Required: Interface<T> Found: StringImplementation at line 11 and Type missmatch: Required: Interface<T> Found: BooleanImplementation at line 12.
Why is that a problem? I though setting <T : Any> in the method contract would allow to return an implementation of any type. The constraing here is that the return type of the method resolve must be Interface<T>, replacing it with Interface<*> would make the compiler shut up but is not what we need.
TL;DR
A function can have exactly 1 return type, but your function has 2 different return types.
Only this would work:
interface Interface<T>
class StringImplementation: Interface<String>
class BooleanImplementation: Interface<Boolean>
class Resolver {
fun resolve(implementation: String): Interface<*> { // <-- star
return when (implementation) {
"string" -> StringImplementation()
"boolean" -> BooleanImplementation()
else -> throw IllegalArgumentException()
}
}
}
Explanation
Looking from the function definition perspective, it has to have an explicit, clear return type. Interface<T> says it should be something extending Interface and the explicit type T which concrete implementation can be known by the start of execution of the function.
There is no way in your code to know what T will be when you call resolve. How else would you imagine the function to know what it will return back?!
Shortened: A function can have exactly 1 return type, but your function has 2 different return types (Interface<String> / Interface<Boolean>).
Continue to read here if you want to dig down into generics and get a more technical description.
The compiler cannot know if T matches the implementation variable. Even if implementation is string, T could be of another type then String. So you either can erase the generic type like #Neo mentioned or you need to cast the return type.
interface Interface<T>
class StringImplementation: Interface<String>
class BooleanImplementation: Interface<Boolean>
class Resolver {
inline fun <reified T : Any> resolve(): Interface<T> {
return when (T::class) {
String::class -> StringImplementation() as Interface<T>
Boolean::class -> BooleanImplementation() as Interface<T>
else -> throw IllegalArgumentException()
}
}
}
To have more type safety, you can use a reified parameter and use this to resolve the type. (Note that the cast is still necessary)
I though setting <T : Any> in the method contract would allow to return an implementation of any type.
No, it means it has to return an implementation of any type the caller asks for. E.g., in Animesh Sahu's example, resolve<Boolean>("string") must return an Interface<Boolean>, but your implementation of resolve would return a StringImplementation. Of course, it could also be resolve<File>("string") etc.
allow to return an implementation of any type
which the called method chooses is exactly Interface<*>.

Kotlin: generic cast function parameter

Taking my first steps in Kotlin, I'm struggling to find the correct signature for a function that receives an instance of a known class along with the desired output class and then looks in a map of converter lambdas whether the conversion can be done.
Here's an example for Long:
private fun <T> castLong(value: Long, clazz: Class<out T>): T {
// map lookup removed for simplicity
return when (clazz) {
String::class.java -> { value.toString() }
else -> { throw IllegalArgumentException("Unsupported Cast") }
}
}
Where T is the class of the desired return value - let's say String. One should be able to call castLong(aLongValue, String::class.java) and receive an instance of String.
But the compiler says:
Type mismatch: inferred type is String but T was expected
This seems like it should be possible as it is quite straightforward so far but even playing around with reified and other constructs didn't yield any better results.
It happens because it can't smart cast String to T, you have to manually cast it.
Furthermore, since you said you are taking your first steps in Kotlin, I leave here two other "advices" not strictly related to your question:
you can get the class of T making it reified
the brackets of a case using when aren't necessary if the case is one line
private inline fun <reified T> castLong(value: Long): T {
// map lookup removed for simplicity
return when (T::class.java) {
String::class.java -> value.toString()
else -> throw IllegalArgumentException("Unsupported Cast")
} as T
}

How to check generic type in Kotlin?

I have class:
class Generic<T : SuperType>() { ... }
And this code is't correct, but cast s to type T:
fun typeCheck(s: SuperType) {
when(s) {
is T -> // Do something
}
}
If use: s as T - this cast will show warning (unsafe cast).
How check that s is T type?
If you need to check if something is of generic type T you need to to have an instance of Class<T> to check against. This is a common technique in Java however in Kotlin we can make use of an inlined factory method that gets us the class object.
class Generic<T : Any>(val klass: Class<T>) {
companion object {
inline operator fun <reified T : Any>invoke() = Generic(T::class.java)
}
fun checkType(t: Any) {
when {
klass.isAssignableFrom(t.javaClass) -> println("Correct type")
else -> println("Wrong type")
}
}
}
fun main(vararg args: String) {
Generic<String>().checkType("foo")
Generic<String>().checkType(1)
}
Generic types are not reified on the JVM at runtime, so there's no way to do this in Kotlin. The warning is correct because the compiler can't possibly generate any instruction that will fail when the cast is done, so the cast is unchecked, meaning that the program may or may not break at some point later instead.
A related feature which might be of use is reified type parameters in inline functions. Classes can't have reified type parameters though, so if you elaborate a bit more on your use case, I can try helping you achieve what you seem to need.
I know that I'm kinda late to this thread, but I just want to recap on the answer provided by Alexander Udalov.
It is, indeed, impossible to determine the type of a generic parameter in Kotlin unless you're using inline functions and declaring the generic type as reified.
Not sure if I'll be able to answer this question entirely and accurately, but I feel like my contribution might still be valuable for someone who is attempting to do just that. So let's say you have a few data classes, and you want to check which type you're dealing with.
You could use a function like that:
inline fun <reified T> checkType() = when (T::class) {
TypeA::class -> println("TypeA")
else -> println("Type not recognized")
}
however, functions that call it must also be inline, so you might have to write something like
inline fun <reified T> someOtherFunction(data: T) {
checkType<T>
}
however, if you cannot allow for an inline function (let's say in an interface!), you can kinda 'cheat' the system by saying, for example
class AmazingTypes {
inline fun <reified T> checkType(genericParameter: T) = when (T::class) {
TypeA::class -> println("TypeA")
else -> println("Type not recognized")
}
}
fun myAwesomeMethod(someParameter: Any) {
val amazingClass = AmazingClass()
amazingClass.checkType(someParameter)
}
This is also example.
inline fun <reified T: ApiResponse> parseJson(body: String): T {
// handle OkResponse only
val klass = T::class.java
if (klass.isAssignableFrom(OkResponse::class.java)) {
return T::class.java.newInstance()
}
// handle others
return gson.from(body, T::class.java)
}