https://kotlinlang.org logo
Title
h

Hullaballoonatic

06/19/2019, 5:53 PM
I mean, I understand why this interaction works this way, but it still makes me sad ☹️ https://pl.kotl.in/_g7Nag0rP in my particular use case, it'd be nice if the
Bar1
was also added to
foos
, but I imagine in other cases, that would be horrendous
r

Ruckus

06/19/2019, 5:57 PM
What about that makes you sad?
h

Hullaballoonatic

06/19/2019, 5:57 PM
i updated the message
r

Ruckus

06/19/2019, 6:01 PM
Hm, why does the constructor of
Bar1
not throw? You can't do
'+=
on
null
h

Hullaballoonatic

06/19/2019, 6:02 PM
oh, because foos hasn't been instantiated yet?
r

Ruckus

06/19/2019, 6:05 PM
It looks like
Bar1
isn't actually instantiated till it's used:
class EffectBuffer<P : Any>(val key: String, type: PaintType<P>) {
    val blend = ShaderProperty.dynamic(
        type.blendType,
        "Blend",
        "Blending Mode",
        type.defaultBlend
    )

    val shaders = mutableListOf<Shader<P>>()
}

abstract class Foo(val name: String = "Foo") {
    init {
        println("Instantiating $name")
        foos += this
        println(foos)
    }

    override fun toString() = name
}

object Bar1 : Foo("Bar1")

val foos = mutableListOf<Foo>()

fun main() {
    val bar2 = object : Foo("Bar2") {}
    foos.forEach(::println)
    println(Bar1.name)
}
s

streetsofboston

06/19/2019, 6:05 PM
foos
is not null. You can have forward declarations. Circular declarations may have some weird behavior, though.
h

Hullaballoonatic

06/19/2019, 6:05 PM
hmm, that's actually really interesting
learning experience!
r

Ruckus

06/19/2019, 6:06 PM
Indeed, that could be useful information.
s

streetsofboston

06/19/2019, 6:06 PM
If the ‘dependency’ tree is a-cyclical, Kotlin can figure out when to instantiate what vals/vars
abstract class Base(val base: Base?, val id: Int) {
    init {
        println("Initing $base with id $id")
    }
}

object A: Base(B, 1)
object B: Base(A, 2)

fun main() {
    println("{$A.base} and ${B.base}")
}
Cyclical ; not sure if behavior is defined or undefined, but I guess you shouldn’t count on it 🙂
h

Hullaballoonatic

06/19/2019, 6:10 PM
ah, good to know
r

Ruckus

06/19/2019, 6:11 PM
Interesting, because this seems to work fine (neither
val
is
null
):
object A {
    val b = B
}

object B {
    val a = A
}

fun main() {
    println(A.b)
    println(B.a)
}
l

louis993546

06/19/2019, 6:12 PM
all you need to do is to use
Bar1
https://pl.kotl.in/z0dp394Jk
s

streetsofboston

06/19/2019, 6:12 PM
But to your point, initialization is somewhat lazy: try
abstract class Base(val base: Base?, val id: Int) {
    init {
        println("Initing $base with id $id")
    }
}

object A: Base(B, 1)
object B: Base(A, 2)

fun main() {
    println("Main")
    println("{$A.base} and ${B.base}")
}
You’ll see that
Main
is printed before the
Initing ..
ones
Main
Initing null with id 2
Initing cycle.B@2c7b84de with id 1
{cycle.A@3fee733d.base} and null
👍 1
h

Hullaballoonatic

06/19/2019, 6:16 PM
@Ruckus I think because when you call
println(A.b)
it instantiates A, which then calls B to set A.b, so now B is being instantiated, which then calls A to set B.a, which is already instantiated
💯 1
🤔 1
s

streetsofboston

06/19/2019, 6:18 PM
More evidence
object
initialization is a bit lazy.
👆 1
h

Hullaballoonatic

06/19/2019, 6:18 PM
@louis993546 I guess this is a case for ping!
fun Any.ping() = this