Search code examples
kotlingradlegradle-plugingradle-kotlin-dsl

Gradle Extensions: can plain Kotlin types be used instead of Property<T> for properties with simple values?


The Gradle docs for lazy configuration states that in extension/DSL classes, properties like var someProperty = "default value" should actually be val someProperty: Property<String> = objectFactory.property(String::class.java).convention("default value"). This is to avoid unnecessary computation during the configuration phase;

I wonder if there is any downside in using plain types for simple values. The benefits are clear to me in case of computation or I/O, but if anything, for simple values I’d say a plain type would result in slightly less resource use during configuration (one less object created and no method calls).

The main reasons I prefer plain property types for simple values is simplicity and especially that the assignment operator can be used in a build script with Kotlin DSL, e.g. someProperty = "foo". I find this cleaner than someProperty.set("foo") and the latter is also imperative, while Gradle DSLs are otherwise mostly declarative.

It seems to work fine and in the task there would still be a Property<String> counterpart that can be initialized with someProperty.set(extension.someProperty), but since the documentation doesn’t mention it as a possibility for simple values, I’m wondering if there is a good reason for it that I couldn’t think of.


Solution

  • In addition to avoiding unnecessary computation during the configuration phase, using a property allows you to avoid race conditions with afterEvaluate clauses. Extension values set by build scripts are NOT available at configuration time.

    Therefore, your example of task.someProperty.set(extension.somePlainField) will not work.

    Using task.someProperty.set(extension.someProperty) (the method with signature set(value: Provider<T>)) makes sure that extension.someProperty.get() is not invoked until the task executes and reads its Property.

    in order to achieve your goal of a fluent extension api, the recommended approach is to add a method to your extension such as

    fun someProperty(value: String) {
      someProperty.set(value)
    }
    

    then, build scripts can use it like:

    myExtension {
      someProperty("my value")
    }