// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[gradle_types_intro]]
= Gradle Managed Types

Gradle Managed Types are the building blocks for writing modern, efficient, and cache-friendly build logic.

image::gradle-basic-12.png[]

When writing build logic, you’ll often reach for standard Groovy or Kotlin types.
However, Gradle provides its own managed types that are lazy, making them far better suited for build logic.

These types enable:

- Incremental builds
- Build cache support
- Configuration cache compatibility
- Accurate tracking of task inputs and outputs

For example, instead of using a `String`, you should use a `Property<String>`:

====
include::sample[dir="snippets/gradle-types/example/groovy/app",files="build.gradle[tags=demo]"]
====

[source,bash]
----
$ ./gradlew demoTask
----
----
include::{snippetsPath}/gradle-types/example/tests/gradleTypes.out[]
----

This example showcases that:

- *Eager values* are computed immediately when the script is loaded (configuration phase).
- *Lazy values* (like `Property` or `Provider`) defer computation until the task is executed (execution phase).

It's always best to ensure Gradle evaluates task logic only during the execution phase to avoid wasting time during configuration.
Using lazy types and values in Gradle ensures builds are fast, efficient, and compatible with performance features like incremental builds, the Build Cache, and the Configuration Cache.

== Common Managed Types

Here is a list of common Gradle managed types you can use in your build logic:

[cols="~,~,~", options="header"]
|===
| Type                  | Purpose                                               | Use-Case

| `Property<T>`         | Lazy scalar value (e.g., a version number)            | A version string
| `ListProperty<T>`     | Lazy list of values (e.g., compiler args)             | A list of compiler args
| `MapProperty<K, V>`   | Lazy map of values (e.g., environment vars)           | A map of Maven Pom properties
| `RegularFileProperty` | Lazy reference to a single file (input or output)     | A single file input/output
| `DirectoryProperty`   | Lazy reference to a directory (input or output)       | A destination directory
| `Provider<T>`         | Lazily evaluated, read-only value (e.g., task output) | A dependency on task output
|===

Gradle distinguishes between *eager* and *lazy* evaluation to control **when** values are computed and **how** they participate in up-to-date checks, caching, and task wiring.
Let's review the differences one more time:

== Eager Evaluation

* Happens **immediately** during the configuration phase.
* Values are resolved *as soon as the line is executed*.
* Prevents Gradle from optimizing build logic.

[source,kotlin]
----
val version = project.version.toString()         // evaluated now
val file = File("build/output.txt")              // evaluated now
myTask.outputFile.set(file)
----

These eager values are resolved even if the task isn’t run, breaking configuration cache compatibility and reducing build performance.

== Lazy Evaluation

* Defers computation until it’s actually needed (usually during task execution).
* Enables Gradle to apply caching, parallel execution, and configuration avoidance.
* Fully supports configuration cache and incremental builds.

[source,kotlin]
----
val outputFile: RegularFileProperty = project.objects.fileProperty()
outputFile.set(layout.buildDirectory.file("output.txt"))    // evaluated later
----

Here, nothing is resolved immediately—Gradle delays evaluation until it’s actually required.

Let's take a look at an example.

== Example

This task will break the Configuration Cache due to *eager* access:

[source,kotlin]
----
// ❌ Not Configuration Cache compatible
tasks.register("printVersion") {
    doLast {
        val version = project.version.toString()
        println("Version is $version")
    }
}
----

The fix: use a *lazy* `Provider` or a `Property<String>`:

[source,kotlin]
----
// ✅ Configuration Cache compatible
tasks.register("printVersion") {
    val version: Property<String> = project.objects.property(String::class.java)
    version.set(project.version.toString())
    doLast {
        println("Version is ${version.get()}")
    }
}
----

[.text-right]
**Next Step:** <<dependencies_intermediate.adoc#dependencies_intro,Learn about Declaring and Managing Dependencies>> >>
