What was the `<<` (leftShift) operator on tasks, why was it removed, and what replaces it?
answer
- << = leftShift = doLast shorthand
- Groovy DSL only
- removed in Gradle 5.0
- hid config-vs-action distinction
- replace with doLast {}
basics
~20 sIn old Groovy DSL, task foo << { ... } was shorthand for adding a doLast action. It was deprecated in Gradle 3.x and removed in Gradle 5.0 because it blurred configuration vs action code. Use doLast { } instead.
solid answer
~40 sThe `<<` (leftShift) operator was a Groovy-DSL shortcut: `task foo << { ... }` appended the closure as a `doLast` **action**. It looked convenient but caused a common bug — beginners assumed the closure body *was* the task body and put **configuration** code inside it, which then ran at execution time instead of configuration time, breaking ordering and dependencies. Because it obscured the crucial configuration-vs-action distinction, Gradle **deprecated** `<<` around 3.x and **removed** it in **Gradle 5.0**. The fix is explicit: write `tasks.register("foo") { doLast { ... } }`, putting wiring in the configuration block and work inside `doLast`. The removal was part of a broader push (lazy task configuration, the Provider API) to make the two phases unambiguous. Knowing this mainly matters when reading legacy Groovy build scripts.
code
groovy · 7 lines// Old (removed in Gradle 5.0):
// task hello << { println 'Hello' }
// Modern replacement:
tasks.register('hello') {
doLast { println 'Hello' }
}go deeper
Just recognize that << is old syntax replaced by doLast; details optional.
Explain that << was a Groovy doLast shorthand, removed in Gradle 5.0, and why it confused config vs action.
Use it to illustrate the broader move toward explicit, lazy task APIs and migration concerns.
Frame around modernizing legacy Groovy build scripts during org-wide Gradle upgrades and enforcing current idioms.
## The old shorthand In early Groovy-DSL Gradle you could write: ```groovy task hello << { println 'Hello' } ``` The `<<` (leftShift) operator was overloaded on `Task` to mean 'append this closure as a `doLast` action'. So the above was equivalent to: ```groovy task hello { doLast { println 'Hello' } } ``` ## Why it was a footgun The operator hid the distinction between the **configuration block** and an **action**. A frequent mistake: ```groovy task build << { dependsOn someOther // WRONG: runs at execution time, too late to affect the graph } ``` Here `dependsOn` (a configuration concern) ends up inside a `doLast` action, executing during the execution phase when it can no longer influence task ordering. New users were repeatedly bitten because `<<` made the action block look like 'the task'. ## Deprecation and removal - **Deprecated**: Gradle 3.2 era. - **Removed**: **Gradle 5.0** — using `<<` is now a build error. ## What to use instead Be explicit and lazy: ```kotlin tasks.register("hello") { group = "demo" // configuration doLast { println("Hello") } // action } ``` This makes it obvious which code configures and which code does work, aligning with configuration avoidance (`register` over `create`) and the modern lazy APIs. In Kotlin DSL `<<` never existed at all; it was purely a Groovy artifact. ## Interview relevance Low on its own, but it signals you understand the configuration-vs-action split and can read/maintain legacy Groovy scripts during migrations.
- What concrete bug did << encourage in beginners' scripts?Putting configuration code (like dependsOn or property setters) inside the action block, so it ran during the execution phase, too late to affect the task graph.
- Did the Kotlin DSL ever support <<?No. leftShift was a Groovy-only operator overload on Task; the Kotlin DSL always required explicit doFirst/doLast.
saying these in an interview costs you the question
- Claiming << still works in current Gradle.
- Saying << added a doFirst action (it added doLast).
- Thinking << was a Kotlin DSL feature.