How do you initialize a non-nullable property as a this pointer in a kotlin data class? - kotlin

Given a Kotlin data class, how do you initialize a non-nullable property as a pointer to self? I.e something like the following pseudocode.
data class Node(var other: Node = this)
Currently I have a solution that introduces temporary properties
data class Node(val _other: Node? = null) {
var other: Node = _other ?: this
}

This is not possible. You cannot access this before it is constructed. But that's just how the default constructor parameter would work.
Cannot access '<this>' before superclass constructor has been called

Thank you for your feedback, however, for my purposes I need the functionality of a data class like equals and copy and I would prefer not to have make the property nullable and/or implementing the functionality manually.
You'd still have to: equals and copy will care only about _other and ignore other (just as they would ignore all other properties defined in the body of the class). That other is a var just makes it worse: reassigning it will have no effect on data class functionality.
But you can come closer:
data class Node(private var _other: Node? = null) {
var other: Node
get() = _other ?: this
set(value) {
_other = if (value != this) value else null
}
}
The only problem remaining is that component1() will return _other. In this case you have a single property so it shouldn't matter.
EDIT: after thinking a bit more,
data class Node(private var _other: Node? = null) {
init {
this._other = _other ?: this
}
var other: Node
get() = _other!! // safe
set(value) {
_other = value
}
}
seems to effectively be what you want. You can see difference here:
val node1 = Node()
val node2 = node1.copy(node1)
println(node1 == node2)
prints false with the first solution, true with the second one (as it should if this was the default parameter).

Related

How to Observe LiveData with custom pair class in Kotlin

I am trying to observe the LiveData for the method which returns custom pair having 2 values. I want the observable to be triggered when I change either one of the values. But it is not getting triggered. Following is the code:
CustomPair.kt
data class CustomPair<T, V>(
var first : T,
var second : V
)
Observable:
falconViewModel.getPlanet1Name().observe(this) {
planet1.text = it.first
planet1.isEnabled = it.second
}
Getter and setter methods in ViewModel falconViewModel
private val planet1EnabledAndText = MutableLiveData<CustomPair<String, Boolean>>()
fun getPlanet1Name() : LiveData<CustomPair<String, Boolean>> {
return planet1EnabledAndText
}
fun setPlanet1Name(planetName : String, visibility : Boolean) {
planet1EnabledAndText.value?.run {
first = planetName
second = visibility
}
}
Can't we observe the value in such case? Please help what is wrong here.
It started working when I tried to set a new value of CustomPair instead of modifying the existing values in the object.
Replaced
planet1EnabledAndText.value = CustomPair(planetName, visibility)
with
planet1EnabledAndText.value?.run {
first = planetName
second = visibility
}
and it worked.

How to deal with nullable values in Iterator implementation in 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
}
}
}

Kotlin access backing field in other place?

I find it can only access backing field in the set or get.Is there any way can access backing field in other place at class?
for example.
var width:Int=0
get() {
return field*10;
}
set(value) {
field=value/10;
}
I want to access the real value but not it multiple 10
when i using c#,there are no field keyword so always need to declare a new variable to store the real data.In the previous example it's will be something look like
private var _width=0;
var width:Int
get() {
return _width*10;
}
set(value) {
_width=value/10;
}
so if i want to access real value in the class,i can just access _value.
But in kotlin,is there have someway can just access backing field without these verbose declaration?
No. Your C# example works fine in Kotlin, it's called a backing property.
Kotlin, You can use backing properties
Backing Properties
If you want to do something that does not fit into this "implicit backing field" scheme, you can always fall back to having a backing property:
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
In all respects, this is just the same as in Java since access to private properties with default getters and setters is optimized so that no function call overhead is introduced.

Can a field be cast to non null version of itself?

I have a data class
data class MyModel(private val _data: MyData? = null)
And I want to ensure my data is only accessible when it is not null, else throw.
I use the below which is good.
fun getData(): MyData {
return checkNotNull(_data) { "data shouldn't be null" }
}
However, if I follow the guide as per Override getter for Kotlin data class, the below complaints I need to return MyData? instead of MyData
val data = _data
get(): MyData {
return checkNotNull(field) { "data shouldn't be null" }
}
Is it true that field can't be cast to the Non-null version of it when return?
If your goal is to declare a getter for a Any? property that returns a Any, it's not possible. You'll get the following error:
Getter return type must be equal to the type of the property
So attempting to do something like
val test : String?
get() : String = "hi"
Wouldn't work.
However, you could hide the nullable property and expose a non-nullable property which references the nullable value via casting:
private val test : String? = "hi"
val testNotNull : String = test as String
If test referenced null, an exception will be thrown.
For example:
fun main(args: Array<String>) = print(Demo().testNotNull)
class Demo(private var test: String? = "hi") {
val testNotNull : String
. get() = test as String
}
You can test this snippit out at try.kotlin.org
Although this is not safe. You should rethink your design. If you're not interoping with Java, you shouldn't punish yourself with nullable types.
I don’t think you can. What you did with the fun getData() is a valid approach IMO. Or you could just not use a data class and create a normal class, obviously.
What I think it may work is with something like this:
typealias notNullType = MyData
data class Test(private val _value: MyData? = null) {
val v: notNullType = _value as notNullType
get() { return field }
}
This would totally allow you to do:
fun play() {
val t = Test(null)
print(t.v) //see what I did? :-)
}
THAT BEING SAID… I don’t think “hiding” the ? optional is necessarily a good idea.
It doesn't necessarily mean that the MyData class is null if you cast it like MyData?
The '?' Just allows the object to be null in the instance that it actually becomes null to avoid an exception at runtime.
You can make your class nullable and it can still contain your data.

Accessing field of a different instance of the same class in Kotlin

Consider this Kotlin code:
var parent: T? = null
get() = if (isParent) this as T else field
set(value) { field = if (value == null) null else value.parent }
val isParent: Boolean
get() = parent == null
var description = ""
get() = if (isParent) field else parent!!.description
set(value) { if (isParent) field = value else parent!!.description = value }
Assume that isParent returns true if this instance is a parent instance. If not getParent() will return the parent instance. In Java you are allowed to access directly field of a different instance of same class like this:
String getDescription() { return getParent().description; }
void setDescription(String value) { getParent().description = value; }
(I am not saying that is a best thing to do, I simplified it for demostration). Comparing to Java, it would be nice to be able to do following:
var description = ""
get() = parent.field
set(value) { parent.field = value }
However this does not work and unfortunately it makes the code less readable. Especially if you have a lot of such variables, which are bound to this parent.
A backing field of a property can only be accessed from a getter or setter of that property, and only for the instance on which the getter or setter has been invoked. If you need to provide multiple ways to access an attribute of a class, you need to define two distinct properties, one of which has a backing field to store the data and another has a getter and setter referring to the first property.
class Foo {
var parent: Foo? = null
val parentOrSelf: Foo get() = parent ?: this
private var _description: String? = null
var description = ""
get() = parentOrSelf._description
set(value) { parentOrSelf._description = value }
}