Kotlin, remove duplicates from Linkedlist : smart cast is impossible - kotlin

I implemented a LinkedList in kotlin and wrote a method to remove duplicates from it:
class Node (value:Int) {
var value = value
var next:Node? = null
fun addNodeToTail(value:Int){
var node = this
while (node.next != null) {
node = node.next
}
val newNode= Node(value)
node.next= newNode
}
fun removeDuplicates (){
val set = HashSet<Int>()
var node = this
set.add(node.value)
while(node.next != null){
if (set.contains(node.next?.value)){
node.next= node.next?.next
}else{
set.add(node.next.value)
node= node.next
}
}
}
}
In the last two lines:
set.add(node.next.value)
node= node.next
(and in the addNodeToTail method), the compiler says that smart cast is impossible because of complex expression. I have to add non-null asserted call (!!).
I want to understand why this solution is not accepted, although the while expression checks that node.next is not null. And I want to know if there is a better solution than using non-null asserted call (!!).
Thank you for your help

Pawel technically answered in the comment.
Basically smart casts are not always possible. In particular, if you define a mutable var of nullable type that is technically accessible by multiple threads, the compiler cannot guarantee that the value stays the same between the null check and the usage. That's why you get this error "smart cast impossible".
A common way of dealing with the problem is to store the value in a local val variable, to guarantee that this value will not change, and allow the compiler to smart cast it.
In your case though, it's not ideal because the while has to check the actual node's value every time. So you'll have to assert that the value is not null at some point, either with !! or with an elvis (?:) and an error() or throw.
I would personally go for:
while (node.next != null) {
val nextNode = node.next ?: throw ConcurrentModificationException()
if (set.contains(nextNode.value)) {
node.next = nextNode.next
} else {
set.add(nextNode.value)
node = nextNode
}
}

Related

Is it considered bad convention when in iterating through two maps, I don't check if key exists in one of them?

I have two maps, let's call them oneMap and twoMap.
I am iterating through all the keys in oneMap, and if the key exists in twoMap I do something
like
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
if (twoMap.containsKey(oneMapKey)) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
}
To avoid having more nested if statements, I was wondering if instead I could get rid of the
if (twoMap.containsKey(oneMapKey)) check. if twoMap doesn't contain the oneMapKey, we get a null object, and my code still works fine. I was wondering if this is considered bad convention though
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
It depends. Do you wanna execute the "more stuff" or not?
If you do not wanna execute it you should keep the if condition. Though, if you are concerned about indentation (and deep if hierarchies) you can consider breaking out of the loop:
for((oneMapKey, oneMapVal) in oneMap) {
if (!twoMap.contains(oneMapKey)) continue // continue with next iteration
// do more stuff
}
If your map does not contain null values you can also get the value and check if the result was null (which means the key was not present in the map):
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal: Any = twoMap[oneMapKey] ?: continue // continue with next iteration
// do more stuff
}
So its always good practice the remove useless code and (in my opinion) to have less if-hierarchies, as you can easily loose focus when you have lots of nested conditions.
As Tenfour04 says, omitting the containsKey() check is only an option if the map values aren't nullable; if they are, then []/get() gives no way to distinguish between a missing mapping and a mapping to a null value.
But if not (or if you want to ignore null values anyway), then I'd certainly consider omitting the check; the resulting code would be slightly shorter and slightly more efficient, without losing clarity or maintainability.  It could also avoid a potential race condition.  (Though in a multi-threaded situation, I'd be considering more robust protection!)
One variation is to use let() along with the safe-call ?. operator to restrict it to non-null cases:
for ((oneMapKey, oneMapVal) in oneMap) {
twoMap[oneMapKey]?.let { twoMapVal ->
if (twoMapVal == oneMapVal) {
// Do more stuff
}
// Do more stuff
}
}
Using ?.let() this way seems to be a fairly common idiom in Kotlin, so it should be fairly transparent.

Smart Cast with hashmap keys

I'm porting some Java apps to Kotlin, and I keep running into this issue with hashmaps. Let's say I have two hashmaps:
var firstHashmap: HashMap<String, String> = hashMapOf("foo" to "A", "bar" to "B")
var secondHashmap: HashMap<String, String> = hashMapOf("foo" to "C", "bar" to "D")
And I want to update one if the same key exists in the other:
if (firstHashmap["foo"] != null) {
secondHashmap["foo"] = firstHashmap["foo"]
}
Kotlin won't compile the second line because firstHashmap isn't guaranteed to have a "foo" key. It doesn't matter that I just checked it on the first line -- the smart cast system apparently doesn't work with hashmap keys. This has the same issue:
if (firstHashmap.containsKey("foo")) {
secondHashmap["foo"] = firstHashmap["foo"]
}
This works, but creating the extra variable gets messy in some situations:
val newValue = firstHashmap["foo"]
if (newValue != null) {
secondHashmap["foo"] = newValue
}
This also works, but so far I've never had to use the !! modifier:
if (firstHashmap["foo"] != null) {
secondHashmap["foo"] = firstHashmap["foo"]!!
}
And this works, but the default value after the Elvis operator will never be used, and is just there to satisfy the compiler, which feels wrong:
if (firstHashmap["foo"] != null) {
secondHashmap["foo"] = firstHashmap["foo"] ?: ""
}
Taking that further, I tried dispensing with the conditional and just using the Elvis operator, but then it gets stuck on secondHashMap not having a guaranteed key:
secondHashmap["foo"] = firstHashmap["foo"] ?: secondHashmap["foo"]
So then this would work, but that brings me back to adding a default value just to trick the compiler:
secondHashmap["foo"] = firstHashmap["foo"] ?: secondHashmap["foo"] ?: ""
Is there a better way to handle this, like some way to trigger the smart cast system to know that the key is really there? Otherwise I guess the !! option seems cleanest, especially when it's clear from the previous line why I'm choosing to use it.
There's no guarantee that firstHashmap["foo"] returns the same value each time it's called. Smart casting is limited to things that are guaranteed not to change, for example val without custom getters in the local module.
You can use
firstHashmap["foo"]?.let {
secondHashmap["foo"] = it
}
to only set the value on secondHashmap if it was not null.

Simplify testing of a null variable in an IF statement

In Kotlin I have this (which will not compile):
var list: MutableList<String>? = null
if (list.isNotEmpty()) {
}
This will compile:
var list: MutableList<String>? = null
if (list!!.isNotEmpty()) {
}
However, if list is null, a runtime exception will occur. I could do this:
var list: MutableList<String>? = null
if ((list != null) && list.isNotEmpty()) {
}
But this seems to be repetitive everywhere you need to test if something is null. Is there a more eloquent way of doing this in Kotlin?
In the specific case of checking if the list is not null or empty you can use:
if (!list.isNullOrEmpty())
For a list, it's better to avoid handling null state instead handle only empty and non-empty state. refer http://thefinestartist.com/effective-java/43.
Saying that, we don't need to explicitly check for null check and only empty check alone should do the trick.
var list : MutableList<String> = mutableListOf()
list.add("Test1")
list.takeIf { it.isNotEmpty() }?.forEach { println(it) }
We can use
takeIf
to check whether the list is empty or not.
The first way add this line
list = list?:MutableList<String>()
Second way
val isEmpty = list.isEmpty()?:false
if(isEmpty){}else{}
Third way
if (!list.isNullOrEmpty())
as #AndroidDev suggested
Why are getting an error? Since !! require non-null. if the object is null then it will throw NPE
I think most can be done with the safe operator ?. itself. So if you just want to iterate over the list (or reduce, map, or whatever), you can just simply do so directly:
val sumExpression = list?.joinToString("+") { it.someValue } ?: throw exception? use default value?
list?.forEach { println("an entry in the list: $it") } // if there are entries, just iterate over them... if not, there is nothing to do
list?.also {
consume(it) // consume now is only called if the list is not null
}
Enhancing it then with a condition is also rather easy with takeIf or takeUnless (depending on what you require):
list?.takeIf { it.isNotEmpty() }
Now you still have a nullable list and can again call any of the desired functions as shown before:
list?.takeIf( it.isNotEmpty() }?.also {
consume(it)
}
Also a variant instead of list.isNullOrEmpty() (already shown by gpuntos answer) is to compare the possible null value to the expected outcome, e.g.:
if(list?.isNotEmpty() == true) {
// do something with the non-empty list
}
In case it is null the condition simplifies to basically null == true which is false. However I wouldn't overuse that too much as then you don't see the actual nullable types so easily anymore. Such a usage may make sense, if what you are trying to calculate isn't already supported in its own extension function (as is with isNullOrEmpty()), e.g. for entering the if only if the count is 4 it makes sense to use something like: if (list?.count() == 4)...

How can I find the first element's method result that is not null?

So I have parsers and want to use the first that does return a non-null value. How would I do that most elegantly?
return parsers.map { it.parse(content) }.firstOrNull { it != null }
would map all (million?) parsers before picking the first.
return parsers.firstOrNull { it.parse(content) != null }?.parse(content)
would run the (expensive?) parse() once again.
I know I can
for (parser in parsers) {
val result = parser.parse(content)
if (result != null) {
return result
}
}
return null
parsers.forEach { it.parse(content)?.run { return this } }
return null
is the shortest I can get but it's not nice to read.
I'm pretty sure there is a shortcut here that I don't see.
Use a sequence. It makes your computation lazy, so that you will only compute parse as many times as you need.
return parsers.asSequence()
.map { it.parse(content) }
.find { it != null }
As an alternative to the overhead of a Sequence, or mapping lots of values unnecessarily, you could use an extension method such as:
inline fun <T, R> List<T>.firstMappedNotNull(transform: (T) -> R): R? {
for (e in this)
return transform(e) ?: continue
return null
}
This uses the minimum of mapping function calls and temporary objects.  It's necessarily written in an imperative way, but it's quite short, and makes your own code short, clear, and functional.
(This version returns null if the list was empty or every mapping returned null.  You could of course change the signature and last line to throw an exception instead.)
It's a shame this function isn't already in the standard library.  But it's easy to add your own!
Also, you can use the following code:
parsers.asSequence()
.mapNotNull { it.parse(content) }
.first()

Kotlin let versus != null

What is the difference between using kotlin's object?.let {...} versus if(object != null) {...}? I've run into the situation where using let on a non-null equates to false and the block is not executed but using the if statement with the same object results in properly identifying that the object non-null and the block is executed.
Do they differ on the low level somehow?
Under the hood, object?.let { } will be compiled to if (object != null) { }. You can try to check the kotlin bytecode.
IMHO, using let also may benefit you to chaining function which makes your code declarative, and I think it is more readable.
One of the scenario where let keyword is preferable when you are reading the list of items that also contains null values and you wants to print only not-null values.
For Example:-
var array = arrayOf("StackOverflow", "Kotlin", "Android", null, "Jetpack", null)
for (item in array) {
item?.let {
print("$it ")
}
}
Output:
StackOverflow Kotlin Android Jetpack
Code inside for loop is like saying "if item is not null, let's print its value". Therefore ?.let allows you to run code for a value that's not null.