user1785730
user1785730

Reputation: 3525

Unexpected closure resolution

Consider this snipped:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(R.layout.test, container, false)

    class MyViewHolder(val view: View): RecyclerView.ViewHolder(view) {
        init {
            view.setOnClickListener {
                Log.d("hey", "there")
            }
        }
    }

    view.findViewById<RecyclerView>(R.id.files).adapter = object: RecyclerView.Adapter<MyViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val item = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
            return MyViewHolder(item)
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.view.findViewById<TextView>(R.id.text).text = files[position].name
        }

        override fun getItemCount() = files.size
    }

    return view
}

onCreateView creates a local variable view. The nested class MyViewHolder also declares a variable called view. What was unexpected is that the variable view accessed inside the init block of MyViewHolder (where the OnClickListener is set) is not the one declared in MyViewHolder, but the outer one. Why?

  1. I would expect the innermost variable declaration would be used.

  2. The class is not declared as an inner class. Outside variables should not be accesible.

What am I missing?

Upvotes: 0

Views: 42

Answers (1)

Alexey Soshin
Alexey Soshin

Reputation: 17701

This is not the case of a nested class, but of a function that returns a class.

If you try to define your class as inner, you'll actually get an error message:

Modifier 'inner' is not applicable to 'local class'

I'll simplify this example a bit, so the Android part won't interfere:

// This is what you're doing
fun a(): Any {
    val a = "a"

    class B(val a: String = "b") {
        init {
            println(a)
        }
    }

    return B()
}

// This is what you think you're doing
class A(val a: String = "a") {
    class B(val a: String = "b") {
        init {
            println(a)
        }
    }
}

fun main() {
    // This refers to function called a
    val func = a()
    
    // This refers to a nested class called B
    val nestedClass = A.B()
}

If you actually want to refer to the local class properties, use this

Upvotes: 1

Related Questions