Home > Mobile >  What is the scope of outer class that has an inner lambda expression
What is the scope of outer class that has an inner lambda expression

Time:06-17

I apologize for the bad title because i have difficult to find the correct way to describe my issue. So i will try to achieve it by a code:

    class CompetitionDetailsViewHolder() : RecyclerViewHolder(binding.root) {

        fun bind(competitionDetailsData: CompetitionDetailsData) {
            binding.apply {
                val topItemSections = sectionsMap?.get(true)?.take(2) ?: emptyList()
                setSectionVisibility(topItemSections) {.....}
                ....
                ....
            }
        }
        
         private fun setSectionVisibility(
            sections: List<GeneralCompetitionDetailsSection>,
            block: (sections: List<GeneralCompetitionDetailsSection>, isVisible: Boolean) -> Unit) 
        {
            block(sections, sections.isNotEmpty())
        }
}

I can't understand how the code: setSectionVisibility(topItemSections) {.....} works? The issue i see here is: binding.apply gets a lambda expression. inside the lambda expression the keyword this refers to binding object, therefore i can't understand how the method setSectionVisibility which belongs to CompetitionDetailsViewHolder class can be called by implicit this (which as i already say refers to binding object)?

CodePudding user response:

inside the lambda expression the keyword this refers to binding object,

Yes

therefore i can't understand how the method setSectionVisibility which belongs to CompetitionDetailsViewHolder class can be called by implicit this

"Implicit this" is exactly the key here. You are not saying this.setSectionVisibility, just setSectionVisibility without any qualifications. This makes all the difference.

When resolving calls, calls with an explicit receiver and calls with an implicit receiver are handled differently, as specified in the two different sections in the language spec: calls with an explicit receiver, calls with an implicit receiver.

Here is a quote from the latter section, describing how it works:

For an identifier named f the following sets are analyzed (in the given order):

  1. Local non-extension callables named f in the current scope and its upwards-linked scopes, ordered by the size of the scope (smallest first), excluding the package scope;

  2. [...]

When analyzing these sets, the first set which contains any callable with the corresponding name and conforming types is picked for c-level partition, which gives us the resulting overload candidate set.

As you can see, it tries to find methods named setSectionVisibility "in the current scope and its upwards-linked scopes". The scope of the CompetitionDetailsViewHolder class is an upwards-linked scope of the scope of the apply lambda, and that is where it will find setSectionVisibility.

Note that if there is also a method called setSectionVisibility with the same signature on the binding object, then that method will be called instead, not CompetitionDetailsViewHolder.setSectionVisibility.

On the other hand, assuming binding does not have an accessible method called setSectionVisibility, this.setSectionVisibility fails to compile because in the "call with explicit receiver" section it is specified that:

A call of callable f with an explicit receiver e is correct if at least one of the following holds:

  1. f is an accessible member callable of the classifier type type(e) or any of its supertypes;
  2. f is an accessible extension callable of the classifier type type(e) or any of its supertypes, including top-level, local and imported extensions.
  3. f is an accessible static member callable of the classifier type e.
  • Related