Why doesn't my println statement get hit? ```val ...
# getting-started
c
Why doesn't my println statement get hit?
Copy code
val supabase = createSupabaseClient(
    supabaseUrl = "",
    supabaseKey = ""
) {
    install(Auth)
    println("SUPABASE INIT")
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            
        }
    }
}
If I update to
Copy code
setContent {
        supabase    
}
then it will print. It's as if createSupabaseClient is acting lazy... but it shouldn't be.
j
what's
createSupabaseClient
?
c
Copy code
inline fun createSupabaseClient(supabaseUrl: String, supabaseKey: String, builder: SupabaseClientBuilder.() -> Unit) = SupabaseClientBuilder(supabaseUrl, supabaseKey).apply(builder).build()
j
Is the
val supabase
declaration actually in the same file?
c
no
I'm trying to get the github reference to it. since its open source code
1 sec
j
If it's a top-level variable, it won't be initialized until the class that represents your file is loaded, and that won't happen until you use something from the file
c
🤔
j
So
createSupabaseClient
is not lazy, but the initialization of
val supabase
as a whole is
🤔 1
c
here's the full convo https://kotlinlang.slack.com/archives/C06QXPC7064/p1726801984414839 this behavior seems to be surprising the maintainer. 😄
j
If you add another variable in the same file as
val supabase
, and reference that other unrelated variable instead from
setContent
you will probably see your print too
c
oh
sorry
I misread your question
Is the
val supabase
declaration actually in the same file? (edited)
Yes. It is in the same file
j
I meant is the
val supabase
declaration in the same file as your activity?
c
Copy code
package com.example.supabase1

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.supabase1.ui.theme.Supabase1Theme
import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient

val supabase = createSupabaseClient(
    supabaseUrl = "",
    supabaseKey = ""
) {
    install(Auth)
    println("SUPABASE INIT")
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Supabase1Theme {
            }
        }
    }
}
Yes
j
Oh ok
c
im just trying supabase. and in my suppppper simple app. im not seeing it init. and i was confused. so i asked in #C06QXPC7064 but yeah. the author also seems perplexed. not sure if this is a bug somewhere in kotlin, or if Im just missing something basic. lol
j
Oh wait. It doesn't matter if it's in the same file. It matters if it's in the same class. And it's not
So basically your above code compiles to 2 classes. One is
NameOfFileKt
and the other is
MainActivity
. If nothing from
NameOfFileKt
is used (meaning no top-level property or function from your file), then it won't be initialized
c
interesting
do you know why this works?
Copy code
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.e("XYZ", "")
        setContent {
            Supabase1Theme {
                buildString
            }
        }
    }
}

val supabase = createSupabaseClient(
    supabaseUrl = "",
    supabaseKey = ""
) {
    install(Auth)
    println("SUPABASE INIT")
}

val buildString = buildString {
    println("buildstring INIT")
    append("hello world")
}
the above ^ prints both printlns. Even though I never call supabase
j
Yes, that's what I told you above, as soon as you use a single thing from the top level declarations, the class that represents the file is loaded, and thus all non-lazy properties are initialized
c
okay. very interesting.
i learned something new.
so basically everything outside of
Copy code
class MainActivity : ComponentActivity() {
is a different file techncially
@Jan if you're curious ^
j
Sort of. Rather a different class. All top-level properties and functions in Kotlin actually end up in an implicit class named after the file, but all type declarations are their own classes.
And the second piece of the puzzle is that, on the JVM, class loading is lazy; but when a class loads, it's entirely initialized.
c
gotcha. i wonder if the same thing would happen in java
j
Java doesn't have top-level declarations, that's why Kotlin generates a class to make the JVM happy 🙂
c
or. i guess I wouldn't be able to declare a variable outside of a class in java
gotcha
okay.
To drive the point home I did this
Copy code
package com.example.supabase1

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.supabase1.ui.theme.Supabase1Theme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Supabase1Theme {
            }
        }
    }
}
and then another file Blah.kt
Copy code
package com.example.supabase1.ui

import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient

val supabase = createSupabaseClient(
    supabaseUrl = "",
    supabaseKey = ""
) {
    install(Auth)
    println("SUPABASE INIT")
}

val built = buildString {
    println("buildstring INIT")
    append("hello world")
}
and in this case. it makes sense to me why
built
or
supabase
aren't init'd
j
Yeah for Kotlin this is the same situation as before
👍 1
And if you do:
Copy code
package com.example.supabase1

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.supabase1.ui.theme.Supabase1Theme
import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Supabase1Theme {
            }
        }
    }
}

object MyOtherClass {
    val supabase = createSupabaseClient(
        supabaseUrl = "",
        supabaseKey = ""
    ) {
        install(Auth)
        println("SUPABASE INIT")
    }

    val built = buildString {
        println("buildstring INIT")
        append("hello world")
    }
}
It's also the same, modulo the class names of course
❤️ 1
c
alright. last question.
Copy code
package com.example.supabase1

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.supabase1.ui.theme.Supabase1Theme
import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient

val supabase = createSupabaseClient(
    supabaseUrl = "",
    supabaseKey = ""
) {
    install(Auth)
    println("SUPABASE INIT")
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Supabase1Theme {
            }
        }
    }
}
If I have the above... is there any easy way to load the
supabase
variable containing class without calling it in MainActivity?
like. i want createSupabaseClient to be called. but I don't want to call
supabase
in my MainActivity code
I know that might be a stupid request. but im trying to see if theres some way i can make sure the other class gets loaded without having to call it specifically
j
Mmmh I struggle to understand the use case. Who will be the consumer of the side effect? Because at the moment you access stuff from the side effect, you probably would need the
supabase
variable, right?
c
I guess i just want the app to have the auth already loading for the MainActivity
So I would probably just do the "right thing" and create an Application class and call the supabase initialization there.
j
Ah I see. Unfortunately I haven't done Android dev in a very very long time, so I don't know the best practices for things that you want to initialize globally.
Is it just for performance or for correctness? From the initial thread it seemed like you were getting a null session or something. If it's for correctness maybe the library could be designed differently, so you cannot get a null session if there is one that's loading. Maybe a
suspend
client creation that would only finish when the session is loaded or something. (I really don't have domain knowledge, so I might be speaking nonsense)
j
So
createSupabaseClient
is not lazy, but the initialization of
val supabase
as a whole is
Yea that makes sense, forgot that top level Kotlin declarations work like that.
I guess i just want the app to have the auth already loading for the MainActivity
You could really just do something simple like this:
Copy code
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Supabase1Theme {
                   var loaded by remember { mutableStateOf(false) }
                   LaunchedEffect(Unit) {
                           supabase.auth.awaitInitialization()
                           loaded = true
                   }
                   if (loaded) {
                       //App
                   } else {
                       CircularProgressIndicator()
                   }
            }
        }
    }
}
Or use the
sessionStatus
state flow as described in the other thread. What is to note here that initialization/loading doesn't only mean to read the session data from the FS. The data gets read and then maybe the session has to be refreshed (API call) and only after that the session is available in the SupabaseClient. The refresh operation can also fail due to e.g. network problems, so you have to also handle that. (Everything reflected in the
sessionStatus
API)
c
Yeah. I mean. I think normally this is a non-issue. it was more breaking my brain because i wasn't sure how I got into this sort of scenario.
anyway. thanks everyone for teaching. now that i think about it. i think i had this same exact issue in a ktor server app because i had a db connection declared outside of the main app. and i ended having to have my first line of my ktor server just be
db
so that it would init the db that was outside of that class.
phew. okay. always learning 💪 Thanks everyone for teaching!
😄 1
j
Happy to help! Usually these things are non-issues (and rather desirable) because you won't face initialization issues unless you access something, but if you do access it then it will be initialized first 😄
c
exactly. so even though the example was contrived. it did legitimately throw me in a loop as to why my supabase auth code wasn't running.
j
Fair enough 🙂