Why doesn't configure(...live collection...) impact Tasks added later?

Is there a reason that the following does not configure iTest?

configure(project.tasks.withType(Test)) {
 jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=256M']
}
  task iTest(type: Test) {
}

but the following does?

project.tasks.withType(Test).all {
 jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=256M']
}
task iTest(type: Test) {
}

The semantics of ‘configure()’ are: iterate over this list and perform the given function against each element.

The semantics of the “live” methods are: perform this function against each element.

For the live methods, the “collection” retains the functions and applies it to future elements. ‘configure()’ can’t do this.

Hope that helps.

Thanks for the fast reply Luke. I guess I could have worded this a bit better.

I understood what was happening, but it seemed a bit surprising that configure was iterating over the collection rather than being aware it was a live collection. The reason I find this surprising is that so many other places within the Gradle DSL treat live collections as a first class citizen (i.e. Java Classpath, dependsOn, etc). Additionally, I don’t know why someone would not want to configure tasks added in the future.

Is there a reason why configure chooses to iterate over the values rather than treating it as a live collection? Is there an easy way to know if Gradle is not going to treat it as a live collection?

Thanks again! Rob

The rule is: nothing is live collection aware, except the methods on live collections.

Once again thanks for your fast reply. Sorry, but I think I am still missing something.

Task.dependsOn is defined on Task and not a live collection. However, Task.dependsOn supports live collections. For example:

task a << {
 println 'a'
}
  task b(dependsOn: project.tasks.matching { it.name != 'b'}) {
 doLast {
  println 'b'
 }
}
  task c << {
 println 'c'
}
$ gradle b
:a
a
:c
c
:b
b

Is there something I am missing or is the rule slightly more complex?

Right, there’s a little more to it… kinda.

‘dependsOn’ doesn’t really support live collections explicitly. What it does is retain the values and iterate them at the latest possible time, regardless of whether they are live or not. This is in contrast to doing a defensive copy. This pattern (i.e. not doing a defensive copy) is used in quite a few places. The documentation for each method should indicate this in some way.

FWIW we aren’t really enamoured with this pattern. It proved powerful and useful to a point, but at a certain level of complexity it becomes hard to reason about. We are slowly moving in a different direction of using dependent functions instead of lazy data structures. This will be a slow, guided, transition though.

Thanks for your patience with me and for the the clarification. I guess this leads to yet another question…

If the Gradle team doesn’t really like the use of live collections, should I be doing something different or must I wait until Gradle makes some enhancements? I’m asking as I would like to try to do things “the most up to date Gradle way”.

Specifically, if I am wanting to change the jvmArgs for every task that extends Test, should I use live collections or should I avoid this? If I should avoid it, what is the preferred way?

Thanks!

I’d use live collections for this.

Live collections are likely to always be around, and we’ll continue to use them where they make sense.

My comment was more that we are finding cases where they aren’t quite the right thing and are working on infrastructure to better deal with these cases.

Thanks…that clears up everything for me

Good luck with it :slight_smile: