null properties in init block kotlin - kotlin

I do not understand why in this code values of i and s are 0 and null respectively in init{} block but in second constructor of class B these values are 200 and param2?
class A(override var i: Int, override var s: String) : B(200, "param2","param3") {
init {
println(i)
println(s)
}
}
open class B(open var i: Int, open var s: String) {
init {
println("class B init")
println("i in init B2 is $i")
println("s in init B2 is $s")
}
constructor(i: Int, s: String, s2: String) : this(i, s) {
println("second constructor B")
println(" i = $i in second constructor")
println(" s = $s in second constructor")
println(" s2 = $s2 in second constructor")
}
}
fun main() {
val ins2 = A(500, "500S")
}
results:
class B init
i in init B2 is 0
s in init B2 is null
second constructor B
i = 200 in second constructor
s = param2 in second constructor
s2 = param3 in second constructor
500
500S
I need some explication please.

You have 2 warnings in that code, both Accessing non-final property X in constructor (one for i and one for s). Have a read here Kotlin calling non final function in constructor works.
That is the reason you get 0 and null first.
The reason you then get 200 and param2 is because that is what you tell it to do here B(200, "param2","param3").
You aren't creating it with the values from A, you are calling that constructor with those predefined values.
And afterwards, those values are overwritten by the i and s inside A.

Related

Kotlin: determine property name when reference is known

Suppose we have two classes A and B. The framework will require that A will have 0 or more properties that are of type B. The user can have a reference to an instance of B. For simplicity, assume that type B can only be declared within class A.
class A {
private val myFirstB = B(this)
private val mySecondB = B(this)
val listOfB: List<B> = mutableListOf(myFirstB, mySecondB)
}
class B(a: A) {
val myA : A = a
fun doSomething(){
// great stuff
}
}
fun testIt(){
val a = A()
val b1 = a.listOfB[0]
}
Through Kotlin reflection how can we determine the name of the property that is holding the reference to b1 within A when we only have the reference b1. We also know that B has a reference to A. Through the instance B, we can get the instance of A. Using reflection, we can get the properties of A via the declaredMemberProperties property. This can be iterated through to get the names of all the properties. However, I do not understand how to ensure that the name that is retrieved is associated with the reference b1.
As said in comments, your case looks very specific and usually reflection isn't ideal for such cases. The algorithm either has to target this very specific case, including the fact the b1 is always inside a list. Or it would have to support many different cases and "guess" where to look for b1.
Basically, the idea is to get the value of each member and compare it to the searched value:
fun main() {
val a = A()
val b1 = a.listOfB[0]
// prints: "listOfB"
println(findPropertyNameByValue(a, b1))
}
fun findPropertyNameByValue(owner: Any, value: Any): String {
return owner::class.memberProperties.first { prop ->
#Suppress("UNCHECKED_CAST")
val list = (prop as KProperty1<Any, *>).get(owner)
list is List<*> && list.any { it === value }
}.name
}
We can even get "listOfB" from the b1 alone, then the algorithm would have to iterate through members twice, again by guessing if the value is our A or not. But it is technically possible.
After some experimentation, the getter call holds the reference that is needed. Here is some possible code:
import kotlin.reflect.KClass
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.KProperty1
fun main(){
val a = A()
val b1 = a.listOfB[0]
println(b1)
val clz: KClass<out A> = a::class
val properties: Collection<KProperty1<out A, *>> = clz.declaredMemberProperties
for(p in properties){
println(p)
println(p.name)
println(p.getter.call(a))
if (p.getter.call(a)?.equals(b1) == true){
println("This is b1")
}
}
}
class A {
val myFirstB = B(this)
val mySecondB = B(this)
val listOfB: List<B> = mutableListOf(myFirstB, mySecondB)
}
var cnt = 1
class B(a: A) {
val myA : A = a
val s = cnt++
fun doSomething(){
// great stuff
}
}
This has the following output:
ksl.B#4590c9c3
val ksl.A.listOfB: kotlin.collections.List<ksl.B>
listOfB
[ksl.B#4590c9c3, ksl.B#d62fe5b]
val ksl.A.myFirstB: ksl.B
myFirstB
ksl.B#4590c9c3
This is b1
val ksl.A.mySecondB: ksl.B
mySecondB
ksl.B#d62fe5b
As can be seen, the test of if the getter reports that it correctly finds b1

How to access to a specific init block in kotlin

I have a kotlin class with two initialization blocks. My constructor contains two parameters one of type list of String and another of boolean type which can be null.
I wish if I create an instance of my class with a single parameter (list of String) I can only execute the first initialization block and if I create an instance with the two parameters I can execute the second initialization block
class User(val type1: List<String>, val type2: Boolean?) {
init {
println("First initializer block executed ")
}
init {
println("Second initializer block executed ")
}
}
fun main() {
val list1: List<String> = listOf("One", "Two", "Three")
val user1 = User(list1,false)
}
how can i do it please ?
There's no need to have 2 inits. Just make a single init with logic inside to determine what to do. Like this for example:
class User(val type1: List<String>, val type2: Boolean? = null) {
init {
if (type2 == null) {
println("First initializer block executed ")
} else {
println("Second initializer block executed ")
}
}
}

Assign 2 vals in class init block using function which returns Pair

Given a class like this:
class Test {
val A: Car
val B: Truck
init {
(A, B) = returnCarAndTruck()
}
fun returnCarAndTruck() = Pair(Car(), Truck())
}
I want to intialize the vals for A and B using a function which returns a pair but it doesn't seem to work unless I define the vals inside the init block. This means I no longer have reference to them correct? Is it possible to intialize these 2 with a Pair?
The best we have for what you're looking for is the following:
class Test {
val A: Car
val B: Truck
init {
val (a, b) = returnCarAndTruck()
A = a
B = b
}
fun returnCarAndTruck() = Pair(Car(), Truck())
}

Destructuring Declarations in Kotlin

I want to return multiple values from a function. As suggested by another SO answer, I used Destructuring with public class, but the problem is I can't assign the returned destructured result to already existing variables.
data class Result(val res1 :Int, val res2: Int)
class test{
fun retresult():Result{
return Result(2,2)
}
}
fun main(args: Array<String>) {
var var1:Int = 0
var var2:Int = 0
var des = test()
//(var1, var2) = des.retresult() this doesn't work
var1 = des.retresult().res1
var2 = des.retresult().res2 // **works but calls function twice**
}
I don't want to initialize local vals at return point like
val (var1, var2) = des.retresult()
You can assign these two variables without calling the function twice, using with:
fun main(args: Array<String>) {
var var1:Int = 0
var var2:Int = 0
var des = test()
with (des.retresult()) {
var1 = res1
var2 = res2
}
}
Alternatively, your function could take function arguments for setting the results, and then you can pass the setters for these properties. This wouldn't work for local variables, only member properties. If you use C, this is kind of like passing a pointer to a function so it can directly modify a variable rather than returning something.
class Test (var one: Int, var two: Int)
fun doSomething(result1: (Int) -> Unit, result2: (Int) -> Unit) {
result1(2)
result2(2)
}
fun main() {
val test = Test(1, 1)
doSomething(test::one::set, test::two::set)
}
There's an open (and mostly forgotten, it seems) feature request for what you suggested, destructuring assignment to existing variables.

Object expressions, Multiple supertype specification syntax?

I am new to Kotlin. I came across the Object Expressions section of https://kotlinlang.org
Some of the object expression syntaxes are very straight forward to understand,
Create an object of an anonymous class
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
})
Just an object
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
But I am unable to understand the "Object expression with multiple supertypes specified" example given as below:
open class A(x: Int) {
public open val y: Int = x
}
interface B { ... }
val ab: A = object : A(1), B {
override val y = 15
}
What's happening here?
${ab.y} prints 15
but syntax -> ${ab.A.y} is not valid. My understanding of ${ab.A.y} it will print 1 :)
This line here:
val ab: A = object : A(1), B {
means that the class of ab is inherited from class A and implements interface B.
Actually the code example you gave will only compile if you declare and implement the interface. This is a possible implementation:
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun hi()
}
val ab: A = object : A(1), B {
override val y = 15
override fun hi() {
println("hi")
}
}
The expression ${ab.A.y} does not make much sense in this context, because the object ab does not have any field A. A is just the inherited superclass to which you could eventually cast.
It basically creates object ab with class type A with implementation of interface B.
So, let's say your class A has some method foo() & interface B has some method bar(), you can access them both on object ab as it's of class type A with implementation of B.
Hence, here you override variable y with value 15 meaning your superclass variable y will get overridden by value 15 from 1.