2

Let you have some variable and apply, run, let, also, takeIf or with function:

// private lateinit var someAdapter: SomeAdapter

recycler_view.apply {
    this.layoutManager = LinearLayoutManager(context)
    if (this::someAdapter.isInitialized) { // Compilation error.
        this.adapter = someAdapter
    }
}

How to access a value or state of someAdapter?

CoolMind
  • 26,736
  • 15
  • 188
  • 224

4 Answers4

3

You can access it via this@YourClass.adapter. It's called qualified this, you can have a look at the documentation here

Stephan
  • 15,704
  • 7
  • 48
  • 63
  • Thanks, but now I can't get a state: `this@SomeFragment.someAdapter.isInitialized` (`isInitialized` is unresolved). – CoolMind Sep 18 '18 at 12:40
  • I don't know how `SomeAdapter` looks like, but that error says that `isInitialized` is not there, or is private. – Stephan Sep 18 '18 at 12:43
  • It is an inline function, see https://stackoverflow.com/questions/37618738/how-to-check-if-a-lateinit-variable-has-been-initialized. It checks whether `lateinit var` variable has already been initialized. – CoolMind Sep 18 '18 at 12:47
  • Thanks, it helped me in another case, when I accessed a view from nested `run`. – CoolMind Sep 18 '18 at 13:11
3

You can use one of the following.

recycler_view.apply {
    this.layoutManager = LinearLayoutManager(context)
    if (this@OuterClass::someAdapter.isInitialized) { //qualified
        this.adapter = someAdapter
    }
}

Or

recycler_view.apply {
    this.layoutManager = LinearLayoutManager(context)
    if (::someAdapter.isInitialized) { // qualified works for immediate outer scope
        this.adapter = someAdapter
    }
}
Jitendra A
  • 1,568
  • 10
  • 18
  • Welcome @CoolMind – Jitendra A Sep 18 '18 at 14:18
  • I must have been blind... I didn't see that `::someAdapter.isInitialized` on the page yet... until now :-) however I don't think that your comment there is valid... if `someAdapter` would be in any of the outer classes, it will still be accessible as long as there doesn't exist any other member that has the same name. And then it might just catch the wrong ;-) – Roland Sep 18 '18 at 15:58
  • 1
    Yes @Roland, I agree. What i meant was that it will resolve to the variable it finds in the immediate outer scope. But I see your point that it can actually cause confusion – Jitendra A Sep 18 '18 at 18:08
2

Not direct answer, but rather design opinion: lateinit vars are supposed to be used when you're guaranteed to have them set before use.

isInitialized was not even present before Kotlin 1.2, it was only added (opinion ahead) as an error fallback.

If you're getting notInitializedException thats good indicator you're not properly initializing the field, if you explicitly initialize it later then you should use nullable field instead: SomeAdapter?.

Pawel
  • 15,548
  • 3
  • 36
  • 36
  • Agree with you, that's why I sometimes prefer `lateinit var`: it shows, when an application has a problem of events sequence. – CoolMind Sep 18 '18 at 13:01
1

Accessing the outer this is possible via this@OuterClass. But, if you do not have any other someAdapter you can also just omit the this@YourOuterClass and simply use the following instead:

if (::someAdapter.isInitialized) {

So given the following, it is clear that someVar of Outer is meant:

class Outer<T> where T : Any {
  lateinit var someVar : T
  inner class Inner {
    fun isItInitialized() = ::someVar.isInitialized
  }
}

Given the following however:

class Outer<T> where T : Any {
  lateinit var someVar : T
  inner class Inner {
    lateinit var someVar : T
    fun isItInitialized() = ::someVar.isInitialized // now someVar of Inner is used
  }
}

you need to specify this@Outer::someVar.isInitialized if you want to access the outer someVar.

Roland
  • 22,259
  • 4
  • 57
  • 84