-1

Stripped down to the bare essence, my problem is:

class MainActivity : AppCompatActivity() {

    lateinit var testArray: Array<String>
    lateinit var testMap: MutableMap<String, Array<Array<String>>>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        testArray = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
        testMap["a"] = arrayOf(
            arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"),
            arrayOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"))

    }
}

Why do I get this error for testMap...

lateinit property testMap has not been initialized

...but no error for testArray?

Edit for improved question quality: I understand that lateinit variables must be initialised later, before they are used - but isn't that what I am doing? It seems to work with testArray, but not with testMap. Why are they different?

Edit 2: This variation...

testMap = mutableMapOf("a" to arrayOf(
    arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"),
    arrayOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")))

...works.

Taqras
  • 173
  • 1
  • 10
  • 1
    Does this answer your question? [lateinit property mMap has not been initialized](https://stackoverflow.com/questions/53765515/lateinit-property-mmap-has-not-been-initialized) – AgentP Mar 27 '22 at 10:47
  • Not really; to me it seems that question concerns a Google map function that evidently needs some time to initialise, or have a function to wait for initialisation? If my question is similar it is not evident to me why one variable is accepted, but the other is not. Why did you score my question down? How can I improve it? – Taqras Mar 27 '22 at 11:11
  • 1
    The reason I downvoted your question is that I felt you didn't do your research well regarding the problem ... the problem why you are getting this error is .. you are not assigning the lateinit object itself you are accessing a part of lateinit object... how does can you access testMap["a"] ? without initilizing testMap ? note testmap[a] is different from testMap itself... you are not seeing the typo here – AgentP Mar 27 '22 at 11:23
  • 1
    And I downvoted before you make that edit ... even after your edit its still too broad to answer here and opinion based as multiple ways of doing it ... – AgentP Mar 27 '22 at 11:26
  • I see. Thanks for explaining. I think testMap["a"]= is a way to add new entries to a map, according to; https://kotlinlang.org/docs/map-operations.html#add-and-update-entries – Taqras Mar 27 '22 at 11:58
  • Yes now you got it :) – AgentP Mar 27 '22 at 12:34

1 Answers1

0

I don't know if you got what's happening here, but just in case

Usually when you create a field (a top-level variable, not inside a function or anything), you have to initialise it with a value:

// needs to be initialised to something!
val coolString1: String

// now we're going places
val coolString2: String = "ok here"

But sometimes you want to define that variable, but you don't actually have the thing you want to assign to it yet (very common in Android, when the actual setup for Activities and Fragments happens in lifecycle callbacks, long after the object was constructed). You want to initialise it, later. That's what lateinit is for

// has to be a var - and look, you're not assigning a value, and it's fine!
lateinit var coolString: String

fun calledLater() {
    coolString = "sup"
}

So lateinit is you promising to initialise that variable before anything tries to access it. The compiler is trusting you to take care of it.

But did you?

// no array assigned! Will init later
lateinit var testArray: Array<String>
// no map assigned! Will init later
lateinit var testMap: MutableMap<String, Array<Array<String>>>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // assigning that array you promised to! perfect
        testArray = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")

        // trying to add something to a map that hasn't been created yet!
        // you're accessing it before it's been assigned, you broke your promise
        testMap["a"] = arrayOf(
            arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"),
            arrayOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"))
    }

So you haven't actually assigned a map to that variable yet - there's nothing there to add values to. Normally you'd get warned/prevented from doing this kind of thing, but lateinit allows you to take control, tell the compiler "don't worry, I got this" and safely initialise something later without having to make it nullable. But you have the responsibility to make sure it will always be initialised before it's accessed

It's an easy enough fix here - just make a map, you can use mapOf the same way you're using arrayOf if you like, mapOf("a" to arrayOf(... But it's good to know what you need to be aware of in general. lateinit can be really useful, but you need to know what you're doing!

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • Thank you for your explanation. I'm aware of the purpose and pitfalls of lateinit, so the question here is concerning the actual syntax I'm using. To call testmap["a"] is to assign a new map between "a" and the array, and as such should be to assign a map to the map variable? If I instead do as you say and use "mutableMap("a" to arrayOf(...", I get exactly the same error - because it's exactly the same thing I do? – Taqras Mar 29 '22 at 09:33
  • It seems I am wrong. I must apologize - I suddenly got this to work with your solution. I'll mark this as solved. Thank you! – Taqras Mar 29 '22 at 10:18
  • 1
    @Taqras ``testmap["a"] = someArray`` is really calling ``testmap.put("a", someArray)``. That adds a *mapping* between ``"a"`` and ``someArray`` in``testmap`` - you're basically adding a key/value pair to an existing ``Map`` object. But ``testmap`` **hasn't been initialised with a `Map` object yet** - there's nothing there, so there's nothing to call ``put`` on, nothing to add a mapping to, It's an empty space on a shelf with a label under it saying `testmap` - the actual object you need to use isn't there yet. Does that make sense? But the `mapOf(...` syntax creates a new map and populates it – cactustictacs Mar 29 '22 at 18:22