Kotlin reference document said this example is valid.
https://kotlinlang.org/docs/reference/generics.html#upper-bounds
fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>
where T : Comparable<T>,
T : Cloneable {
return list.filter { it > threshold }.map { it.clone() }
}
But in Android studio 3.0, it shows thin red line under it.clone(). And error message is:
Type inference failed. Expected type mismatch. Required: List<T>
Found: List<Any>
Why this example cannot be compiled?
The problem is the use of clone(), which is protected as the compiler complains. The problem's already been discussed here: https://discuss.kotlinlang.org/t/is-the-documentation-correct/2925
Related
I can have
val composeFunction = remember { mutableStateOf ({}) }
I can have
val composeFF = #Composable { Text("ABC") }
val composeFunction = remember { mutableStateOf (composeFF) }
Why can't I have
val composeFunction = remember { mutableStateOf (#Composable { Text("ABC") }) }
It errors out state
Internal Error occurred while analyzing this expression
(Please use the "
" icon in the bottom-right corner to report this error):
jar:file:/Applications/Android%20Studio.app/Contents/lib/platform-impl.jar!/general/error.svg
Type inference failed. Expected type mismatch: inferred type is #Composable () -> Unit but () -> Unit was expected
Have you tried specifying the type?
val composeFunction = remember { mutableStateOf<#Composable () -> Unit> (#Composable { Text("ABC") }) }
Looks like the compiler cannot infer an ordinary function to something that is supplied with a #Composable annotation
Update:
It turns out #Composable annotation actually modifies the function type, similar to what suspend modifier does.
Based on this arcticle,
An important thing to note is that Compose is not an annotation
processor. Compose works with the aid of a Kotlin compiler plugin in
the type checking and code generation phases of Kotlin: there is no
annotation processor needed in order to use compose. This annotation
more closely resembles a language keyword. A good analogy is Kotlin’s
suspend keyword.
furthermore,
The important point here is that when you annotate a function type
with #Composable you’re changing its type: the same function type
without the annotation is not compatible with the annotated type.
Also, suspend functions require a calling context, meaning that you
can only call suspend functions inside of another suspend function.
I am trying to learn kotlin from basic android kotlin codelabs here, where a codelabs explains lambda and higher order functions. It shows an example of higher order function
sortedWith()
we are using this method if we have to sort names list based on string length, as given in the codelab
fun main() {
val peopleNames = listOf("Fred", "Ann", "Barbara", "Joe")
println(peopleNames.sorted())
println(peopleNames.sortedWith { str1: String, str2: String -> str1.length - str2.length })
}
The output of the above is given :
[Ann, Barbara, Fred, Joe]
[Ann, Joe, Fred, Barbara]
which is working fine, if i work on kotlin playground : here
However, if I try to run this code on IntelliJ IDEA, I am getting an error :
Error:(37, 25) Kotlin: Type inference failed: fun <T> Iterable<T>.sortedWith(comparator: kotlin.Comparator<in T> /* = java.util.Comparator<in T> */): List<T>
cannot be applied to
receiver: List<String> arguments: ((String, String) -> Int)
Error:(37, 35) Kotlin: Type mismatch: inferred type is (String, String) -> Int but kotlin.Comparator<in String> /* = java.util.Comparator<in String> */ was expected
Is there anything wrong with my kotlin version? My current kotlin version is :
1.3.50-release-112
Use compareBy
println( peopleNames.sortedWith(compareBy(
{ it.length },
{ it }
)))
output
[Ann, Barbara, Fred, Joe]
[Ann, Joe, Fred, Barbara]
I have a custom Preferences class which uses Kotlin extensions to return a Preference string.
It works perfect in API 28, but won't compile in API 29. With Googles new rules about not allowing app updates that target below API 30, I need to update this app, but can't figure out this basic issue.
Here is my Preference class:
import android.content.SharedPreferences
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class PreferenceProperty<T> internal constructor(
private val getter: SharedPreferences.(key: String, defaultValue: T) -> T,
private val setter: SharedPreferences.Editor.(key: String, value: T) -> SharedPreferences.Editor,
private val defaultValue: T,
private val key: String? = null
) : ReadWriteProperty<SharedPreferences, T> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): T {
return thisRef.getter(key ?: property.name, defaultValue)
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: T) {
thisRef.edit().setter(key ?: property.name, value).apply()
}
}
fun SharedPreferences.stringPreference(defaultValue: String): PreferenceProperty<String> {
return PreferenceProperty(
SharedPreferences::getString,
SharedPreferences.Editor::putString,
defaultValue
)
}
fun SharedPreferences.nullableStringPreference(defaultValue: String? = null): PreferenceProperty<String?> {
return PreferenceProperty(
SharedPreferences::getString,
SharedPreferences.Editor::putString,
defaultValue
)
}
I am using the stringPreference, but also need nullableStringPreference for other parts of the code.
I use it as follows:
var notificationToken: String by stringPreference("")
But I get this error:
Type inference failed. Expected type mismatch: inferred type is PreferenceProperty<String?> but PreferenceProperty<String> was expected
So the issue is that, since API 29, it returns String?.
Does anyone know change in API29 caused this and how to work around it?
Thanks
Weird. There must have been something changed in how nullability annotations are interpretted to make it stricter. I don't see any signature or annotation change on the getString() method between the two versions of the SDK. Logically, this is the correct treatment of the return value since it's marked #Nullable. There's no annotation for the return value to match the nullability of a method parameter.
You can replace
SharedPreferences::getString
with
{ key, def -> getString(key, def)!! }
To get it working again. !! is logically safe here, but if you're pedantic about avoiding it you could use:
{ key, def -> getString(key, null) ?: def }
I am trying to cast object and it sometime crashes when object has an image url. But it works fine when I am using only string. How can I understand and resolve the issue?
val sourcedata : LinkedHashMap<String, MutableList<Any>> = somefunction()//this line is ok
var parsedData: LinkedHashMap<String, MutableList<String>> =
Gson().fromJson<LinkedHashMap<String, MutableList<String>>>(Gson().toJson(sourceData))!!
Also my inline function is below
inline fun <reified T> Gson.fromJson(json: String): T? = this.fromJson<T>(json, object :
TypeToken<T>() {}.type)
Issue appears is -
Cannot evaluate the expression : Backend (JVM) Internal Error
Occurred : Failed to generate expression. KTObjectLiteral expression
You might want to type-check, before attempting to type-cast.
For example (just debug to see which data-types need to be considered).
if(sourcedata is LinkedHashMap<String, MutableList<String>>) {
} else if(sourcedata is LinkedHashMap<String, MutableList<Uri>>) {
} else if(sourcedata is LinkedHashMap<String, MutableList<Any>>) {
}
Without having seen that part, you might not be adding the expected type to sourcedata already. When not being able to mix data-types, you could as well use two kinds of MutableList<>.
And I really wonder what you are trying to accomplish there:
Gson().fromJson< ... >(Gson().toJson(sourceData))
I have the following simple Kotlin extension functions:
// Get the views of ViewGroup
inline val ViewGroup.views: List<View>
get() = (0..childCount - 1).map { getChildAt(it) }
// Get the views of ViewGroup of given type
inline fun <reified T : View> ViewGroup.getViewsOfType() : List<T> {
return this.views.filterIsInstance<T>()
}
This code compiles and works fine. But, I want the function getViewsOfType to be a property, just like the views. Android Studio even suggests it. I let AS do the refactoring and it generates this code:
inline val <reified T : View> ViewGroup.viewsOfType: List<T>
get() = this.views.filterIsInstance<T>()
But this code doesn't compile. It causes error: "Type parameter of a property must be used in its receiver type"
What is the issue here? Searching for help on this error doesn't seem to lead to an answer.
The error means that you can only have a generic type parameter for an extension property if you're using said type in the receiver type - the type that you're extending.
For example, you could have an extension that extends T:
val <T: View> T.propName: Unit
get() = Unit
Or one that extends a type that uses T as a parameter:
val <T: View> List<T>.propName: Unit
get() = Unit
As for why this is, I think the reason is that a property can't have a generic type parameter like a function can. While we can call a function with a generic type parameter...
val buttons = viewGroup.getViewsOfType<Button>()
... I don't believe a similar syntax exists for properties:
val buttons = viewGroup.viewsOfType<Button> // ??