Why is my "List<String>" being interpreted as "List<String>?" - kotlin

class Example(private val childrenByParent: HashMap<String, List<String>>) {
private val parents: List<String> = childrenByParent.keys.toList()
fun getChildrenCount(parentPosition: Int): Int {
return childrenByParent[parents[parentPosition]].size
// error, recommends using "?." or "!!"
}
}
The compiler won't let me call size directly but I don't understand why. There are no nullable types in sight.
If I let the compiler infer the type by doing this:
val infer = childrenByParent[parents[parentPosition]]
I can see that it assumes it's a List<String>?
It seems that I'm quite confused about nullability still. Would appreciate some help. I have a feeling I'm doing something incredibly dumb, but after some searching and testing I failed at fixing this.
I would like for this function to not use ?. or even worse, !!. Is it possible? At least, using HashMap and List<String>.

HashMap.get(Object) returns null when there is no element matching the key you provided, so its return type is effectively nullable, regardless of whether the values are or not.
So unfortunately you have to account for the case in which the key doesn't exist, so your choices are either implementing a case where it doesn't, or just declaring it as non-null with !! if you are sure the key exists.
Otherwise you can use HashMap.containsKey(String) to ensure the key exists and then you can be confident that using !! on the value won't result in a NullPointerException.
However as #gidds pointed out, this is not naturally thread-safe without some more work, so it might be best to just handle the case of the key not being in the map. Also I cannot actually think of many cases where you could be sure that key exists, in which a Map is the most appropriate data structure to use.
Also, even though this is not the case here, remember that nullability is just a feature of Kotlin, so when using some classes originally written in Java, whether an element is nullable or not is unknown. The IDE will usually represent this as Type! where the single ! tells you it is a platform type.

Related

Should I use an explicit return type for a String variable in Kotlin?

In Kotlin, We can declare a string read-only variable with type assignment and without type assignment (inferred) as below.
val variable_name = "Hello world"
or
val variable_name: String = "Hello world"
I'm trying to figure out what is the best in Kotlin and why it is the best way. Any idea?
If this is a public variable, using an explicit return type is always a good idea.
It can make the code easier to read and use. This is why your IDE probably shows the return type anyway, even when you omit it from the code. It's less important for simple properties like yours where the return type is easy to see at a glance, but when the property or method is more than a few lines it makes much more difference.
It prevents you from accidentally changing the type. With an explicit return type, if you change the contents of the property so that it doesn't actually return the correct type, you'll get an immediate compile error in that method or property. With an implicit type, if you change the contents of the method you could see cascading errors throughout your code base, making it hard to find the source of the error.
It can actually speed up your IDE! See this blog post from the JetBrains team for more information.
For private variables, explicit return types are much less important, because the above points don't generally apply.
Personally either one works and for me nothing is wrong, but I would choose the later if this is a team project, where project size increase and feature inheritance(members leaving, new hiring or worse shuffling people) is probable. Also I consider the later as more of a courtesy.
There are situations where regardless of the dogma every member follows, such as clean architecture, design-patterns or clean-coding, bloated codes or files are always expected to occur in such big projects occasionally, so the later would help anyone especially new members to easily recognize at first glance what data type they are dealing with.
Again this this is not about right or wrong, as kotlin is created to be idiomatic, I think this is Autoboxing, it was done in kotlin for codes to be shorter and cleaner as few of its many promise, but again regardless of the language, sometimes its the developer's discretion to have a readable code or not.
This also applies with function return types, I always specify my function return types just so the "new guy" or any other developer will understand my function signatures right away, saving him tons of brain cells understanding whats going on.
fun isValidEmail() : Boolean = if (condition) true else false
fun getValidatedPerson(): Person = repository.getAuthenticatedPersonbyId(id)
fun getCurrentVisibleScreen(): #Composable ()-> Unit = composables.get()
fun getCurrentContext(): Context if (isActivity) activityContext else applicationContext

What is this Kotlin type: (String..String?)

IntelliJ is showing me context hints that my variables are of type (String..String?). I cannot find any mention of it on the internet, what is this type?
(String..String?) represents a flexible type with lower bound String and upperbound String? (nullable string). This is not valid Kotlin code (it's not denotable) but it is used in the compiler internals and thus in IntelliJ's hints sometimes.
(On the JVM we often see platform types using ! as in String!, which are a more specific case of flexible types)
It's Kotlin's way of saying it doesn't know whether the String type declared for payload.email is nullable or not (for instance if this is declared in Java, which doesn't distinguish those), and yet it doesn't want to enforce either of those, for convenience (hence "flexible").
As the name suggests, flexible types are flexible — a value of type (L..U) can be used in any context, where one of the possible types between L and U is needed
This means that even though the actual type of the value is "somewhere between String and String?", values of this type can be used even in places expecting String, even though the real type of that value may be String? and thus the value could be null.
This is useful because assuming it is String would mean that null checks would be marked as redundant, and assuming it is String? would force the developer to write null checks everywhere, even though they might know that this particular Java method cannot return null.
In general, it's a good practice to explicitly declare the type of a variable that you get from Java, to avoid the propagation of the platform type and the uncertainty (and unsafety) that comes with it:
val email: String = payload.email // if you know it cannot be null
val email: String? = payload.email // if you don't know

Same method for nullable and non-nullable arguments

I'm trying to create two almost-same methods that handle nullable and non-nullable arguments slightly differently:
fun parse(type: Any) : MyObject {
return handleParse(type)
}
fun parse(type: Any?) : MyObject? {
if (type == null)
return null
return handleParse(type)
}
But I get this error in Android Studio:
Platform declaration clash: The following declarations have the same JVM signature
The goal is that it automatically handles nullable and non-nullable values in Kotlin, without me using !! every time I call it on nullable terms.
I've already tried adding the #JvmName("-name") annotation as mentioned in this answer but that doesn't work either. Obviously, I can change the method name to something else as well, but that is just circling around and avoiding the issue altogether.
Hoping there's an easy way to do this or at least a sensible workaround. Would also appreciate the reasoning behind the way things currently work, and why I should or shouldn't do this.
Reason why this doesn't work is simple, Java doesn't have null-safe types, meaning that both methods look completely same to Java, and Kotlin aims to provide as much interoperability with Java as possible.
But if you think a bit more about that there is simply no reason for such feature, as you can see your 2nd method already handles everything properly, with addition of 1 if case, which even if this feature exist would have to exist because compiler would need to know whether value in null or not in other to know which method to call anyway.
Common approach that I have seen so far is adding NotNull suffix to your method, for example in your case it would be parseNotNull in case where you don't allow nullable types, this way even when calling code from Java it is clear that parameter shouldn't be null.

What is the difference between not-null checks in Kotlin?

There are some ways to fulfill a null-checking in Kotlin:
1.
if(myVar != null) {
foo(myVar)
}
2.
myVar?.let {
foo(it)
}
3.
myVar?.run {
foo(this)
}
What are the difference between these ways?
Are there any reasons (performance, best practice, code style etc.) why I should prefer on way over the other?
!! is to tell the compiler that I am sure the value of the variable is not null, and if it is null throw a null pointer exception (NPE) where as ?. is to tell the compiler that I am not sure if the value of the variable is null or not, if it is null do not throw any null pointer.
Another way of using a nullable property is safe call operator ?.
This calls the method if the property is not null or returns null if that property is null without throwing an NPE (null pointer exception).
nullableVariable?.someMethodCall()
All three code are behave same null check in operation-wise.
?. is used for chain operations.
bob?.department?.head?.name // if any of the properties in it is null it returns null
To perform a chain operation only for non-null values, you can use the safe call operator together with let
myVar?.let {
foo(it)
}
the above code is good for code style and performance
more details refer Null Safety
The ways 2 and 3 are more idiomatic for Kotlin. Both functions are quite similar. There is little difference with argument passing.
For example, we have a nullable variable:
var canBeNull: String? = null
When you working with T.run you work with extension function calling and you pass this in the closure.
canBeNull?.run {
println(length) // `this` could be omitted
}
When you call T.let you can use it like lambda argument it.
canBeNull?.let {
myString -> println(myString.length) // You could convert `it` to some other name
}
A good article about Kotlin standard functions.
All three are roughly equivalent.
The if case is more like most other languages, and so many developers may find it easier to read.
However, one difference is that the if case will read the value of myVar twice: once for the check, and again when passing it to foo(). That makes a difference, because if myVar is a property (i.e. something that could potentially be changed by another thread), then the compiler will warn that it could have been set to null after the check. If that's a problem (e.g. because foo() expects a non-null parameter), then you'll need to use one of the other cases.
For that reason, the let case has become fairly common practice in Kotlin. (The run case does just about the same thing, but for some reason isn't as popular for this sort of thing. I don't know why.)
Another way around it is to assign myVar to a temporary value, test that, and then use that. That's also more like other languages, but it's more verbose; many people prefer the conciseness of the let case — especially when myVar is actually a complicated expression.
The examples in your question don't show the true reason to decide.
First of all, since you're not using the return value of foo, you should use neither let nor run. Your choice is between also and apply.
Second, since you already have the result you want to null-check in a variable, the difference fades. This is a better motivating example:
complexCall(calculateArg1(), calculateArg2())?.also {
results.add(it)
}
as opposed to
val result = complexCall(calculateArg1(), calculateArg2())
if (result != null) {
results.add(result)
}
The second example declares an identifier, result, which is now available to the rest of the lexical scope, even though you're done with it in just one line.
The first example, on the other hand, keeps everything self-contained and when you go on reading the rest of the code, you are 100% confident that you don't have to keep in mind the meaning of result.
Kotlin have new features with NullPoint-Exception as Compare to Java.
Basically When we do Coding in Java , then we have to Check with !! in every Flied.
But in Kotlin, it is Easy way to Implement First
as Like,
Suppose, in Kotlin
var response:Json?=Null
response:Json?.let {
this part will handle automatic if response is Not Null....then this Block start Executing }?.run {
This is Nullable But, where we Can put Warring } So, I am Suggest you Guys to Start Work in Kotlin with this Features Provided by Kotlin.
(Flied)?.let { Not Null Value Comes Under }?.run{ Null Value Code }
This will Handle to NullPoint Exception or Protect You App for Crash
What you want to achieve
What you want to achieve is that the Kotlin compiler does a smart cast on the variable you are working with.
In all of your three examples, the compiler can do that.
Example:
if(myVar != null) {
foo(myVar) // smart cast: the compiler knows, that myVar can never be null here
}
The choice
Which one of the options to use, is really a matter of style. What you should not do is mix it up to often. Use one and stick to it.
You don't need to worry about performance since let and run are inlined (see inline function). This means that their code (body) is copied to the call site at compile time so there is no runtime overhead.

When working with Java libraries in Kotlin, is it more idiomatic to use ? or !! on method return values?

I'm new to Kotlin and there's a common pattern that I'm not sure how to deal with most correctly. Take this code, for example, which doesn't compile:
git_repo?.add().addFilepattern()
add() is a call in the JGit library which is purely Java, so its return type is AddCommand!.
I have two options:
git_repo?.add()!!.addFilepattern("test.txt")
and
git_repo?.add()?.addFilepattern("test.txt")
Both work fine and given that
I don't know the intricacies of the library implementation,
the documentation of the JGit library doesn't specify whether add() can return null, and
within this context I'd typically expect add() to not return a null
Which version is more idiomatically correct to write in Kotlin? It seems that this would be a fairly common issue to deal with since basically every non-Kotlin library would introduce this issue.
I would use the ?. safe operator and then put your own exception at the end after an ?: Elvis operator. This way you get a message that is meaningful. Using just !! isn't a very helpful message to someone down the road who has no idea what the intricacies were either.
val cmd = gitRepo.add()?.addFilepattern("test.txt") ?: throw IllegalStateException("assert: gitRepo.add() returned an unexpected null")
cmd.doSomething() // never is null guaranteed
If the value is every null you will have a custom error.
assert: gitRepo.add() returned an unexpected null
And after this line, you will not have to null check because the result of the expression is guaranteed never to be null.
If you inspect the code of the other library and ensure it would never ever be null no matter what, then a !! is appropriate. But if not sure, do one better with the custom message.
Note I dropped the first ?. from your example because I'm assuming git_repo itself is not nullable. Plus I renamed it not to have an underscore which isn't normal Kotlin naming convention.
If you are sure that git_repo will always return a value!! is fine in that case.
It is ugly but !! will always be there when you use Java libraries, and you can't avoid it.
The only reason i would use git_repo?.add()?.addFilepattern("test.txt"), would be if you are returning a value, and you want the value to be nullable so that your calling method can handle the nullable.
fun nullableMethod(): string? {
return git_repo?.add()?.addFilepattern("test.txt")
}
fun callingMethod() {
if(this.nullableMethod() != null) {
}
//Else
}
If you are guaranteed it is never going to null, use !!