type inference failed in Kotlin fun - kotlin

translate a springboot java demo into a kotlin one,and run into a type inference failed problem.
it is a repository fun to get back the target result
package tacocloud.data
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Repository
import tacocloud.Ingredient
import tacocloud.Type
import java.sql.ResultSet
import java.sql.SQLException
#Repository
class JdbcIngredientRepository
#Autowired
constructor( private val jdbc: JdbcTemplate) : IngredientRepository {
override fun findAll(): Iterable<Ingredient> {
return jdbc.query("select id, name, type from Ingredient"
) { rs, rowNum -> this.mapRowToIngredient(rs, rowNum) }
}
override fun findById(id: String): Ingredient {
return jdbc.queryForObject(
"select id, name, type from Ingredient where id=?",
{ rs, rowNum -> mapRowToIngredient(rs, rowNum)}, arrayOf(id))
}
#Throws(SQLException::class)
private fun mapRowToIngredient(rs: ResultSet, rowNum: Int): Ingredient {
return Ingredient(
rs.getString("id"),
rs.getString("name"),
Type.valueOf(rs.getString("type")))
}
override fun save(ingredient: Ingredient): Ingredient {
jdbc.update(
"insert into Ingredient (id, name, type) values (?, ?, ?)",
ingredient.id,
ingredient.name,
ingredient.type.toString())
return ingredient
}
}
the findById funtion keeps saying that "Error:(29, 21) Kotlin: Type inference failed. Expected type mismatch: inferred type is Ingredient? but Ingredient was expected".the delegate funtion mapRowToIngredient(rs: ResultSet, rowNum: Int): Ingredient has return a Ingredient,not a Ingredient?
any ideas?
List item

JdbcTemplate, I suppose, is being compiled from Java source code file, and in Java any reference can point to null. That's why queryForObject returns a nullable type - Kotlin tends to treat all Java's references return declarations to be nullable (refer to "platform types" for more info).
And if queryForObject returns null, then the mapper function you provide will be just omitted and null will be returned from the function eventually.
It is possible to either make findById function return a nullable type (change the declaration so that it returns an Ingredient?), specify a default object to return if queryForObject returned null (e.g. jdbc.queryForObject(...) ?: DEFAULT_RESPONSE) or make use of force "unboxing" to the non-null type (e.g. jdbc.queryForObject(...)!!).
P.S.: it is quite common to get an empty response by id querying (e.g. an item by this id was deleted or so) and repositories often return nullable type or throw an exception in such a case, so personally I'd stick to this solution. But if your design guarantees that an item always be present when queried by id, I'd use the !! to cast nullable type to non-nullable by force.

Related

Having trouble with type erasure

I have something like this :
import kotlin.reflect.KClass
class Quantity<T> {
/* ... */
}
class Field<T : Any> {
val type: KClass<T> get() = TODO("This is initialized, don't worry about implentation details, just know that fields know their type.")
fun initValue(value: T) {
/* Do something very useful */
}
/* Other methods */
class Template<T : Any> {
fun initFieldWithValue(value: T): Field<T> {
return Field<T>().apply {
this.initValue(value)
}
}
}
}
class ComponentClass(
val fieldsTemplates: Map<String, Field.Template<*>>
) {
inner class Instance(field: Map<String, Field<*>>)
fun new(fieldValues: Map<String, Quantity<*>>): Instance {
val fields = mutableMapOf<String, Field<*>>()
for ((fieldName, template) in fieldsTemplates) {
fields[fieldName] = fieldsTemplates
.getValue(fieldName)
.initFieldWithValue(fieldValues.getValue(fieldName) /* Here a type error */)
}
return Instance(fields)
}
}
As you might guess, this is intended to work as a 'runtime way' of creating classes that own fields (Field<T> class), each one possessing a typed value (represented by a Quantity<T>).
The problem is that this code won't compile due to the fact that the quantity retrieved from fieldValues when creating the different fields of the future Instance in the new method isn't guaranteed to be of the required type for the field it is stuffed into.
The problem is that I would need a check since filling a Field<Quantity<String>> with a Quantity<Int> is obviously not a good idea, but because of the type erasure I cannot ensure that the quantities passed in are of the good type.
Any idea ? One more thought : Fields know what their type is thanks to their type attribute, but unfortunately I can't do the same for the Quantity class...
Your initFieldWithValue function is enforcing the type of the parameter to match the type known by the Template/Field. But inside your new function, your Template is a Template<*> since you retrieve it from a collection where the values are of this type.
The point of generics is to enforce compile time checks so casting can be done safely and automatically under the hood. This is only useful when your type is known at compile time. In this case, the type is not known at compile time, so the generics are preventing your code from compiling. This is what generics are supposed to do: prevent code from compiling if the compiler cannot check that they types match.
If you want this code to compile, you should change initFieldWithValue so it doesn't enforce generics. You can instead manually check the type and throw an error or exit early if it's incorrect. It will be up to your code elsewhere to ensure you aren't mixing and matching types.
Here's an example of a version that would work. The type check it does requires the Kotlin reflection library. If you're targeting JVM only, you can use the Java Class.isAssignableFrom method instead to do this check.
class Template<T : Any> {
val type: KClass<T> get() = TODO()
/**
* #throws IllegalStateException if [value] is not of the same type
* as this Template's [type].
*/
fun initFieldWithValue(value: Any): Field<T> {
if (!value::class.isSubclassOf(type)) {
error("Invalid value type for Field type of $type")
}
return Field<T>().apply {
#Suppress("UNCHECKED_CAST") // we manually checked it above
initValue(value as T)
}
}
}

Extension method, when called on a null object, is called on the wrong type

fun main() {
val set: Set<Int>?
set = null
val emptySet: Set<Int> = set.orEmpty()
}
Can't figure out why even when explicitly typing the set variable as Set <Int>? the compiler considers that in the extension method set.orEmpty () set - is a string and, accordingly, crashes with an error:
Kotlin: Type mismatch: inferred type is String but Set was expected
But when declaring and initializing in one line, everything happens correctly:
fun main() {
val set: Set<Int>? = null
val emptySet: Set<Int> = set.orEmpty()
}
The behavior you're observing can be explained by the interaction of two Kotlin features:
first, the type of set variable is narrowed to Nothing? as a result of a smart cast after the assignment of null value to it. The smart cast after an assignment can be useful in cases when it narrows variable type to a more specific type, but narrowing to Nothing? does more harm than good.
second, among all overloads of orEmpty function available for a value of type Nothing?, the non-generic one String?.orEmpty() is chosen due to the specific rule of Kotlin overload resolution: a non-generic candidate is preferred to generic ones.
This behavior indeed can be puzzling, so I've reported this problem as KT-50661.
I think this is related to the fact that the compiler is not so smart that it could deduce that the code set = null will be executed exactly once – it could be zero times or more than once.
If you know that it will run exactly one, you can tell the compiler by using a feature called kotlin.contracts:
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
#ExperimentalContracts
fun main() {
val set: Set<Int>?
once { set = null }
val emptySet: Set<Int> = set.orEmpty()
}
#ExperimentalContracts
fun once(lambda: () -> Unit) {
contract { callsInPlace(lambda, InvocationKind.EXACTLY_ONCE) }
lambda()
}
See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/

Kotlin incorrectly infers nullable Enum return type when a function call is passed as an argument to another function

I may not have done a good job explaining the problem in the title, but here's an example:
fun main() {
acceptEnum(inferType())
}
fun acceptEnum(value: MyEnum?) {}
fun <R : Enum<R>?> inferType(): R = TODO()
enum class MyEnum {
VALUE
}
inferType() function infers its return type and bounds it to be a generic nullable enum. acceptEnum() function has a nullable enum parameter. When we write acceptEnum(inferType()), everything's fine. But if we add one more parameter to acceptEnum() and pass inferType() there again, here's what happens:
fun main() {
// first inferType() does not compile with an error:
// Type mismatch: inferred type is MyEnum? but MyEnum was expected
acceptEnum(inferType(), inferType())
}
fun acceptEnum(value: MyEnum?, value2: MyEnum?) {}
If we add more parameters, every inferType() call except the last one produces this error.
Is this a compiler bug or am I doing something wrong?
Update
Kotlin forum post: https://discuss.kotlinlang.org/t/kotlin-incorrectly-infers-nullable-enum-return-type-when-a-function-call-is-passed-as-an-argument-to-another-function/23650
Update
Kotlin issue https://youtrack.jetbrains.com/issue/KT-50232

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.

What is the purpose of having bound class reference return a covariant type?

I'm playing with reflection and I came out with this problem. When using bound class reference via the ::class syntax, I get a covariant KClass type:
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
As I could learn from the docs, this will return the exact type of the object, in case it is instance of a subtype of T, hence the variance modifier.
However this prevents retrieving properties declared in the T class and getting their value (which is what I'm trying to do)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
I found that a solution is using javaClass.kotlin extension function on the object reference, to get instead the invariant type:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
This way, I get both the exact type at runtime and the possibility to consume the type.
Interestingly, if I use a supertype instead of a generic, with the latter method I still get access to the correct type, without the need of variance:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == Derived::class)
}
}
fun main(args: Array<String>) {
val derived = Derived()
foo(derived) // prints 'true'
}
If I got it correct, ::class is equal to calling the java getClass, which returns a variant type with a wildcard, while javaClass is a getClass with a cast to the specific type.
Still, I don't get why would I ever need a covariant KClass, when it limits me to only produce the type, given that there are other ways to access the exact class at runtime and use it freely, and I wonder if the more immediate ::class should return an invariant type by design.
The reason for covariance in bound ::class references is, the actual runtime type of an object the expression is evaluated to might differ from the declared or inferred type of the expression.
Example:
open class Base
class Derived : Base()
fun someBase(): Base = Derived()
val kClass = someBase()::class
The expression someBase() is typed as Base, but at runtime it's a Derived object that it gets evaluated to.
Typing someBase()::class as invariant KClass<Base> is simply incorrect, in fact, the actuall result of evaluating this expression is KClass<Derived>.
To solve this possible inconsistency (that would lead to broken type-safety), all bound class references are covariant: someBase()::class is KClass<out Base>, meaning that at runtime someBase() might be a subtype of Base, and therefore this might be a class token of a subtype of Base.
This is, of course, not the case with unbound class references: when you take Base::class, you know for sure that it's the class token of Base and not of some of its subtypes, so it's invariant KClass<Base>.