How to deal with nullable values in Iterator implementation in kotlin? - kotlin

So I was following the Algorithms book by Sedgewick and trying to translate the implementations from Java to Kotlin and when I tried to implement one Iterator for the Bag data structure (that's essentially a one-way linked list), I got stuck with nullability issues and thread safety in Kotlin.
The implementation in java from the book is done this way:
public class Bag<Item> {
private Node first;
private class Node {
Item item;
Node next;
}
/* some methods */
private class Iterator<Item> {
private Node current = first;
public boolean hasNext() { current != null; }
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
}
which I tried to implement in Kotlin like this:
class Bag<Item> : Iterable<Item> {
private inner class Node(val item: Item, val next: Node?)
private var first : Node? = null
/* Some methods */
override fun iterator() = object : Iterator<Item> {
private var current : Bag<Item>.Node? = first
override fun hasNext() : Boolean = current != null
override fun next() : Item {
if (current == null) throw NoSuchElementException()
val item = current.item
current = current.next
return item
}
}
}
But I got the following error:
Smart cast to 'Bag.Node' is impossible, because 'current' is a mutable property that could have been changed by this time
I understand this is due to race condition between checking if the variable is null and actually accessing the variable attributes, since the variable could be set to null by other threads. After some time I arrived into the following implementation:
override fun iterator() = object : Iterator<Item> {
private var current : Bag<Item>.Node? = first
override fun hasNext() : Boolean = current != null
override fun next() : Item {
current?.let {
val item = it.item
current = it.next
return item
} ?: throw NoSuchElementException()
}
}
And the compiler thought this was fine. But I still have some doubts. Which leads to my questions:
1) Is the assignment current = it.next thread safe or should I assign to the implicit it instead?
2) Is there a idiomatic Kotlin way of implementing an iterator of non-nullable type that ends with a null value? (meaning that all values in it are non-null except for the ending condition)

Is the assignment current = it.next thread safe
It is not thread safe.
Imagine a list of integers and two threads A and B who want to use iterator instance I.
1 -> 2 -> 3 -> 4 -> 5 A: item=1, next=(2)
^ A: item=1, next=(2)
I
Both threads begin to iterate. Both path inside current?.let. Both read current item (val item = it.item) and got item=1, next=(2). Then, first thread A is frozen and second thread B advances the iterator, let's say, by three items forward:
1 -> 2 -> 3 -> 4 -> 5 A: item=1, next=(2)
^ B: item=4, next=(5)
I
Now B enters let and reads next item: item=4, next=(5). Remember that A is still in his loop and it's item is item=1, next=(2). If B is now frozen and A advances one line of code (current = it.next) then things are broken: current is a shared state (as it is stored in the iterator) and, thus, B will see the change as well. On the next iteration in B it will be "thrown back" to the item #2. Nothing bad will happen and the program will not fail, but most probably that is not the behavior you need.
Even more: for the described reasons iterators are not meant to be thread-safe and every thread should have it's own, independent one. Things become more interesting with iterators that change a collection (insertions / deletions), but it's another story as it is about the collection, not about the iterator.
Should I assign to the implicit it instead?
You cannot assign to it, as it is a function parameter and it is passed by value, and, thus, cannot be changed. The compiler will ban the assignment with a message like "Val cannot be reassigned"
Is there a idiomatic Kotlin way of implementing an iterator of non-nullable type that ends with a null value?
I'd say: yes. You could potentially use sealed classes to designate different types of nodes like:
sealed class Node<out T>;
object Empty : Node<Nothing>();
data class Full<T>(val item: T, val next: Node<T>) : Node<T>();
class Bag<T>(private val first: Node<T>) : Iterable<T> {
override fun iterator(): Iterator<T> = object : Iterator<T> {
private var current = first
override fun hasNext() = current !is Empty
override fun next() = when (val c = current) {
Empty -> throw IllegalStateException()
is Full -> {
current = c.next
c.item
}
}
}
}
fun main() {
val bag = Bag(Full(1, Full(2, Full(3, Empty))))
bag.forEach(::println)
}

I was surprised to not see this method listed, which has been available since Kotlin 1.3. You can use the iterator {} helper in conjunction with yield() to easily build an iterator that handles null effectively.
For example, in a LinkedList:
class NamedLinkedListNode(
val name: String,
val next: NamedLinkedListNode?
) : Iterable<String> {
override fun iterator() = iterator {
var node: NamedLinkedListNode? = this#NamedLinkedListNode
while (node != null) {
yield(node.name)
node = node.next
}
}
}

Related

Kotlin property initialization

I've created the following snippet, not anything that I would actually write in production, but just to help me understand how properties are initialized:
class C {
val a: String = run {
println("init a")
f()
}
val b: String = run {
println("init b: a=$a")
a
}
private fun f(): String {
println("f(): a=$a, b=$b")
return b
}
}
fun main() {
println(C().a)
println(C().b)
}
Note that all properties are val and String, so immutable and non-nullable. Yet the output shows that they are null.
Is the result of this code well-defined? Is there somewhere in the language spec that says that a non-nullable property can in fact be null when you access it from the wrong place?
According to the Kotlin/Core spec, the order of the execution is specified,
When a classifier type is initialized using a particular secondary constructor ctor delegated to primary constructor pctor which, in turn, is delegated to the corresponding superclass constructor sctor , the following happens, in this initialization order:
[...]
Each property initialization code as well as the initialization blocks in the class body are invoked in the order of appearance in the
class body;
[...]
but the values of the uninitialised properties are not.
If any of the properties are accessed before they are initialized w.r.t initialization order (e.g., if a method called in an initialization block accesses a property declared after the initialization block), the value of the property is unspecified. It stays unspecified even after the “proper” initialization is performed.
In other words, you will see the messages printed in the order of
init a
f(): a=null, b=null
init b: a=null
null
but the values are not guaranteed to be null.
There might be stronger guarantees in Kotlin/JVM, but there is no spec for that right now.
This is explicitly not an answer, just two small remarks/questions:
First, doesn't one of the three members a, b, or f() need to be set to a or return a value? The way it is in the OPs code, everything is null by definition as there is no non-null value anywhere. The 'call chain' is a –> f() –> b, so if we set b to a value like "start", it would look like this:
class C {
val a: String = run { f() }
val b: String = run { "start" }
private fun f(): String = b
}
fun main() {
val c = C()
println(c.a) // Output: null
println(c.b) // Output: "start"
}
Secondly, if the order is changed so that b is appearing in the code before the other two members we get a different result:
class C {
val b: String = run { "start" }
val a: String = run { f() }
private fun f(): String = b
}
fun main() {
val c = C()
println(c.a) // Output: "start"
println(c.b) // Output: "start"
}

equal() function in Kotlin

I need if two objects are equal() need to print("Equal") if objects are not equal -> "Not equal".I can not find mistake of this codeThis is my code in IntelliJ IDEA
As a side note, when we override equals(), it is recommended to also override the hashCode() method. If we don’t do so, equal objects may get different hash-values; and hash based collections, including HashMap, HashSet, and Hashtable do not work properly (see this for more details). We will be covering more about hashCode() in a separate post.
References:
internal class Complex(private val re: Double, private val im: Double) {
// Overriding equals() to compare two Complex objects
fun equals(o: Object): Boolean {
// If the object is compared with itself then return true
if (o === this) {
return true
}
/* Check if o is an instance of Complex or not
"null instanceof [type]" also returns false */if (o !is Complex) {
return false
}
// typecast o to Complex so that we can compare data members
val c = o as Complex
// Compare the data members and return accordingly
return (java.lang.Double.compare(re, c.re) == 0
&& java.lang.Double.compare(im, c.im) == 0)
}
} // Driver class to test the Complex class
fun main(args: Array<String>) {
val c1 = Complex(12.0, 15.0)
val c2 = Complex(10.0, 15.0)
if (c1 == c2) {
println("Equal ")
} else {
println("Not Equal ")
}
}
In Kotlin, you use Any instead of Object. It will not allow you to test if your class instance is an Object, only Any.
Also, you are failing to override equals since you didn't use the override keyword. The argument needs to be Any?, not Object.
Change
fun equals(o: Object): Boolean {
to
override fun equals(o: Any?): Boolean {
Also, in this case, you should use a data class so you won't have to write your own equals() implementation in the first place.
And in the future, when you aren't using a data class, you can use the IDE option to generate equals and hashcode for you automatically.
A data class would make more sense:
data class Complex(
private val re: Double,
private val im: Double
)
val c1 = Complex(12.0, 15.0)
val c2 = Complex(10.0, 15.0)
if (c1 == c2) {
println("Equal")
} else {
println("Not Equal")
}
Output: Not Equal

Is it possible to null T or 'this' at the end of generic function for Kotlin?

I have in my project a listener. It is assigned to drawerLayout. I would like to in lambda function remove it and null it at once (sequentially). Is it possible to null T or this at the end of generic function.
Here is my code:
// Usage
actionBarListener?.let {
drawerLayout.removeDrawerListener(it) // remove listener
actionBarListener = null // null it
}
// Usage expected
actionBarListener.releaseAndSetNull {
drawerLayout.removeDrawerListener(it) // remove listener and null it
}
// Generic
fun <T> T?.releaseAndSetNull(block: (T?) -> Unit) = apply {
this?.apply { block.invoke(this) }
this = null // Error: variable expected
}
As Ivo Beckers said, this function would only work on vars, i.e. KMutableProperty0<T>. So you could write an extension on KMutableProperty0<T?>, and use reflection to set it, if you don't mind using reflection, that is.
inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T?) -> Unit) {
block(this.get())
this.set(null)
}
// or if you don't want the block to be called if the property is null:
inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T) -> Unit) {
this.get()?.run(block)
this.set(null)
}
Then suppose you have a property:
var foo: Int? = 10
You can do:
::foo.releaseAndSetNull { println("Foo: $it") }
// or if foo belongs to someObject
someObject::foo.releaseAndSetNull { println("Foo: $it") }
Looking at the generated bytecode, the way this is implemented (which is subject to change) is that each unique property referred to by a property reference in this way causes an inner class to be generated. The inner class will then have get and set methods that do their jobs with little extra cost - as they can just set the right property directly. So really the main cost is the extra inner class that is generated.
I can think of several reasons why this could never work.
First of, the generic function doesn't know if this is a var or val. And this functionality could only works on a var
Likewise, it can't know if it's nullable, that's also a requirment.
Furthermore, it can even be the case that it's not a variable that's calling the function.
Like say you have
fun getActionBarListener() {
return actionBarListener
}
Then somewhere else you could do
getActionBarListener().releaseAndSetNull {
drawerLayout.removeDrawerListener(it) // remove listener and null it
}
How do you expect that to work?
Or even anonymous objects could call this function.

MutableStateFlow is not emitting values after 1st emit kotlin coroutine

This is my FirebaseOTPVerificationOperation class, where my MutableStateFlow properties are defined, and values are changed,
#ExperimentalCoroutinesApi
class FirebaseOTPVerificationOperation #Inject constructor(
private val activity: Activity,
val logger: Logger
) {
private val _phoneAuthComplete = MutableStateFlow<PhoneAuthCredential?>(null)
val phoneAuthComplete: StateFlow<PhoneAuthCredential?>
get() = _phoneAuthComplete
private val _phoneVerificationFailed = MutableStateFlow<String>("")
val phoneVerificationFailed: StateFlow<String>
get() = _phoneVerificationFailed
private val _phoneCodeSent = MutableStateFlow<Boolean?>(null)
val phoneCodeSent: StateFlow<Boolean?>
get() = _phoneCodeSent
private val _phoneVerificationSuccess = MutableStateFlow<Boolean?>(null)
val phoneVerificationSuccess: StateFlow<Boolean?>
get() = _phoneVerificationSuccess
fun resendPhoneVerificationCode(phoneNumber: String) {
_phoneVerificationFailed.value = "ERROR_RESEND"
}
}
This is my viewmodal, from where i am listening the changes in stateflow properties, as follows,
class OTPVerificationViewModal #AssistedInject constructor(
private val coroutinesDispatcherProvider: AppCoroutineDispatchers,
private val firebasePhoneVerificationListener: FirebaseOTPVerificationOperation,
#Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
#AssistedInject.Factory
interface Factory {
fun create(savedStateHandle: SavedStateHandle): OTPVerificationViewModal
}
val phoneAuthComplete = viewModelScope.launch {
firebasePhoneVerificationListener.phoneAuthComplete.filter {
Log.e("1","filter auth $it")
it.isNotNull()
}.collect {
Log.e("2","complete auth $it")
}
}
val phoneVerificationFailed = viewModelScope.launch {
firebasePhoneVerificationListener.phoneVerificationFailed.filter {
Log.e("3","filter failed $it")
it.isNotEmpty()
}.collect {
Log.e("4","collect failed $it")
}
}
val phoneCodeSent = viewModelScope.launch {
firebasePhoneVerificationListener.phoneCodeSent.filter {
Log.e("5","filter code $it")
it.isNotNull()
}.collect {
Log.e("6","collect code $it")
}
}
val phoneVerificationSuccess = viewModelScope.launch {
firebasePhoneVerificationListener.phoneVerificationSuccess.filter {
Log.e("7","filter success $it")
it.isNotNull()
}.collect {
Log.e("8","collect success $it")
}
}
init {
resendVerificationCode()
secondCall()
}
private fun secondCall() {
viewModelScope.launch(coroutinesDispatcherProvider.io) {
delay(10000)
resendVerificationCode()
}
}
fun resendVerificationCode() {
viewModelScope.launch(coroutinesDispatcherProvider.io) {
firebasePhoneVerificationListener.resendPhoneVerificationCode(
getNumber()
)
}
}
private fun getNumber() =
"+9191111116055"
}
The issue is that
firebasePhoneVerificationListener.phoneVerificationFailed
is fired in viewmodal for first call of,
init {
resendVerificationCode()
}
but for second call of:
init {
secondCall()
}
firebasePhoneVerificationListener.phoneVerificationFailed is not fired in viewmodal, I don't know why it happened, any reason or explanation will be very appericated.
Current Output:
filter auth null
filter failed
filter code null
filter success null
filter failed ERROR_RESEND
collect failed ERROR_RESEND
Expected Output:
filter auth null
filter failed
filter code null
filter success null
filter failed ERROR_RESEND
collect failed ERROR_RESEND
filter failed ERROR_RESEND
collect failed ERROR_RESEND
Pankaj's answer is correct, StateFlow won't emit the same value twice. As the documentation suggests:
Values in state flow are conflated using Any.equals comparison in a similar way to distinctUntilChanged operator. It is used to conflate incoming updates to value in MutableStateFlow and to suppress emission of the values to collectors when new value is equal to the previously emitted one.
Therefore, to resolve this issue you can create a wrapping class and override the equals (and hashCode) method to return false even if the classes are in fact the same:
sealed class VerificationError {
object Resend: VerificationError()
override fun equals(other: Any?): Boolean {
return false
}
override fun hashCode(): Int {
return Random.nextInt()
}
}
StateFlow is SharedFlow:
https://github.com/Kotlin/kotlinx.coroutines/issues/2034
Described in more detail in my article: https://veldan1202.medium.com/kotlin-setup-sharedflow-31debf613b91
val shared = MutableSharedFlow(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
shared.tryEmit(value)
The value emitted by state flow is conflated and doesn't emit the same consecutive result twice, you can think as if a condition check is validating the old emitted value is not equal to the newly emitted value.
Current Output:
filter auth null
filter failed
filter code null
filter success null
filter failed ERROR_RESEND
collect failed ERROR_RESEND
(filter failed ERROR_RESEND
collect failed ERROR_RESEND) This being the same old value which was emitted so you will not see them getting emitted.
Use a Channel: this does emit after sending the same value twice.
Add this to your ViewModel
val _intent = Channel<Intent>(Channel.CONFLATED)
Put values using send / trySend
_intent.send(intentLocal)
observe as flow
_intent.consumeAsFlow().collect { //do something }
I think I have some more in-depth understanding of this issue. The first thing to be sure is that for StateFlow, it is not recommended to use variable collection types (such as MutableList, etc.). Because MutableList is not thread safe. If there are multiple references in the core code, it may cause the program to crash.
Before, the method I used was to wrap the class and override the equals method. However, I think this solution is not the safest method. The safest way is for deep copy, Kotlin provides toMutableList() and toList() methods are both deep copy. The emit method judges whether there is a change depends on whether the result of equals() is equal.
The reason I have this problem is that the data type using emit() is: SparseArray<MutableList>. StateFlow calls the equals method for SparseArray. When MutableList changes, the result of equals does not change at this time (even if the equals and hashcode methods of MutableList change).
Finally, I changed the type to SparseArray<List>. Although the performance loss caused by adding and deleting data, this also solves the problem fundamentally.
As mentioned above, LiveData emits data every time, while StateFlow emits only different values. tryEmit() doesn't work. In my case I found two solutions.
If you have String data, you can emit again this way:
private fun emitNewValue() {
subscriber.value += " "
subscriber.value.dropLast(1)
}
For another class you can use this (or create an extension function):
private fun <T> emitNewValue(value: T) {
if (subscriber.value == value) {
subscriber.value = null
}
subscriber.value = value
}
But it's a bad and buggy way (values are emitted twice additionally).
Try to find all subscribers that change their values. It can be not evident. For instance, focus change listener, Switch (checkbox). When you toggle Switch, a text can also change, so you should subscribe to this listener. The same way when you focus other view, an error text can change.
Use wrapper object with any unique id, for example:
class ViewModel {
private val _listFlow = MutableStateFlow(ListData(emptyList()))
val listFlow: StateFlow<ListData> get() = _listFlow
fun update(list:List<String>){
_listFlow.value = ListData(list)
}
data class ListData constructor(
val list: List<String>,
private val id: UUID = UUID.randomUUID(),//added unique id
)
}
I had a similar problem after merging the streams.
The emit() function will not be executed if == is used to determine equality.
The way to solve the problem: You can wrap a layer and rewrite the hashCode() and equals() methods. The equals() method directly returns false.
This solution works in my code. The stream after the combine has also changed.
Pankaj's answer is correct, StateFlow will not emit the same value twice.
Before wrapping, the result of == is still true even if the content is different.
You could make _phoneVerificationFailed nullable and send null between the two calls!

Kotlin: How to specify a named arguent with a variable?

Suppose I have two methods:
private fun method1(a: A): A {
return a.copy(v1 = null)
}
private fun method2(a: A): A {
return a.copy(v2 = null)
}
Can I write something like:
private fun commonMethod(a: A, variableToChange: String): A {
return a.copy($variableToChange = null)
}
Another words, can I use a variable to refer to a named argument?
If I understand correctly what you are trying to archive I would recommend to pass a setter to the method e.g.
fun <A> changer (a: A, setter: (a: A) -> Unit ) {
// do stuff
setter(a)
}
Is this what you are looking for?
A possible solution for this problem (with usage of reflection) is:
inline fun <reified T : Any> copyValues(a: T, values: Map<String, Any?>): T {
val function = a::class.functions.first { it.name == "copy" }
val parameters = function.parameters
return function.callBy(
values.map { (parameterName, value) ->
parameters.first { it.name == parameterName } to value
}.toMap() + (parameters.first() to a)
) as T
}
This works with all data classes and all classes that have a custom copy function with the same semantics (as long as the parameter names are not erased while compiling). In the first step the function reference of the copy method is searched (KFunction<*>). This object has two importent properties. The parameters property and the callBy function.
With the callBy function you can execute all function references with a map for the parameters. This map must contain a reference to the receiver object.
The parameters propery contains a collection of KProperty. They are needed as keys for the callBy map. The name can be used to find the right KProperty. If a function as a parameter that is not given in the map it uses the default value if available or throws an exception.
Be aware that this solution requires the full reflection library and therefore only works with Kotlin-JVM. It also ignores typechecking for the parameters and can easily lead to runtime exceptions.
You can use it like:
data class Person (
val name: String,
val age: Int,
val foo: Boolean
)
fun main() {
var p = Person("Bob", 18, false)
println(p)
p = copyValues(p, mapOf(
"name" to "Max",
"age" to 35,
"foo" to true
))
println(p)
}
// Person(name=Name, age=15, foo=false)
// Person(name=Max, age=35, foo=true)