Kotlin variables that are not in scope?

Viewed 102

On https://github.com/mozilla/rust-android-gradle/blob/8183f9e927336011c7c09d75efd4f5f411940db1/plugin/src/main/kotlin/com/nishtahir/CargoBuildTask.kt#L19 we have this kotlin code:

open class CargoBuildTask : DefaultTask() {
    var toolchain: Toolchain? = null


    @Suppress("unused")
    @TaskAction
    fun build() = with(project) {
        extensions[CargoExtension::class].apply {

I'm very confused as from where does extensions come from, as well as project. They aren't local variables, they aren't in a scope or something. What are they?

2 Answers

Inheritance is the answer to project.

CargoBuildTask : DefaultTask()

Do you see how CargoBuildTask inherits properties of DefaultTask? Thus project is a property from DefaultTask. However, extensions is a property from project which is of Type Project.

Read this documentation on DefaultTask and you will have more understanding.

Kotlin's with is the answer to extensions.

In short, with with you can invoke methods without explicitly stating its subject. (Read more here)

For example, these two code snippets mean the exact same thing:

    with("string") {
        substring(3) //invoke method without subject
    }

    "string".substring(3) //Same as above

Here is the method from org.gradle.api.Project

   ExtensionContainer getExtensions();

Now, If you are wondering how Java's getExtensions() turned into Kotlin's extensions, read this. Basically states that traditional Getters and Setters in Java are interpreted as Properties in Kotlin.

PS: If you are unsure of what Inheritance is in OOP/Kotlin, read this.

  1. The projectcomes from the DefaultTask() inherited in the current class. Inheritance is used here which is a very basic concept. Read more about Kotlin's inheritance here.

  2. The extensions comes from project using with which is one of the scope functions.

    Read more about with here. enter image description here.

    For example. Suppose you've a Data class.

    data class PersonModel(val name: String, var age: Int)
    

    And you create a model of it as

    val personModel = PersonModel("Adam", 30)
    

    Now, if you pass it to a with function as a reciever, you can access 'personModel`'s properties directly in the with's scope as:

    with(personModel) {
        //name is the property of personModel
        val nameWas = name
        //Declared var and can be editable.
        age = 31
    }
    

    with works with functions as well where you can pass a function as a reciever to it and it returns the returned value of the function.

    These scope functions (let, run, with, apply, also) are extremely useful in production environment.

Related