// 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.

[[lazy_evaluation]]
= Lazy vs Eager Evaluation

Understanding **when** values in your build are computed is crucial for writing fast and reliable build logic.
Gradle differentiates between *eager* and *lazy* evaluation:

[[eager_evaluation]]
== Eager Evaluation

Values are computed immediately during the **configuration phase**, before tasks ever run.

Eager evaluation comes with drawbacks:

* **Slows down builds** — even when tasks aren’t executed.
* **Breaks compatibility** —  with and configuration caching.

Essentially, eager evaluation performs unnecessary work and reduces flexibility.

[[lazy_evaluation_section]]
== Lazy Evaluation

Lazy values are computed on-demand, typically during the **execution phase**, using Gradle’s Provider API (`Provider<T>` and `Property<T>`).

This approach has key benefits:

1. **Deferred resolution** — values are only computed when needed.
2. **Better performance** — avoids unnecessary computation during configuration.

Lazy evaluation enables build features like incremental builds, build caching, and configuration cache compatibility.

[[lazy_apis]]
== Lazy APIs

Lazy APIs were explicitly designed to avoid configuring tasks that aren’t going to be run, especially in large projects or Android builds where configuration overhead can be significant.

For example, you might use a `String` in your build script, but this value is *eagerly evaluated* during the *configuration phase*.
Instead, you should use Gradle’s `Property<String>` type, which defers evaluation until it’s needed during task *execution*.

Another example which is a common pitfall is using `tasks.withType(Test) {}`:

[source,groovy]
----
tasks.withType(Test) {
    // configure all tasks eagerly
}
----

This eagerly configures all `Test` tasks, even in builds where those tasks may never run.
Instead, use `configureEach`:

[source,groovy]
----
tasks.withType(Test).configureEach {
    // configure only those tasks actually needed
}
----

Or:

[source,groovy]
----
tasks.named("test") {
    // configure only if task will be executed
}
----

This use of `configureEach` and `tasks.named(...)` ensures configurations only apply to tasks invoked by the build.
