On 27.12.2017 10:04, Cédric Champeau wrote:
[...]
The consequence, however, is that any change to a Java class in Groovy core is going to produce a different compiler.

This is fine in the IDE, as long as I do not have to bootstrap immediately... which I do not have to.

But I must say the IDEA setup is still annoying as hell. I freshly generated the modules and ended up with a project I cannot compile, because of the examples. I then switched to build, but ignore errors, which resulted in my main (FileSystemCompiler, GroovyMain) classes not being found, because they have not been compiled and I did not add the Groovy global lib. Then I added the bootstrap and while the main classes now have been found, they have been of course from the bootstrap, not the source. I will always have to have a really, really, really good look at things to see if I am using bootstrap or not. I mean imagine you remove a class and then run from the IDE to see if your test still works. And it will, because the damn class is still in the bootstrap jar, which of course you did not create a new one. I easily lost more than half a day just trying to setup things again. Together with the installation and fixing of intellij itself... that was no fun day at all and lost time for Groovy development.

For Gradle, which is aware of inputs/outputs, it means that the compiler has changed, and that it needs to recompile downstream consumers (subprojects) and, of course, re-execute their tests. This is the _correct behavior_. Gradle is right to do so, because the compiler has changed, so the bytecode generated might be different, but also since Groovy provides a runtime, it also needs to re-execute the tests because the runtime has changed.

What I explain is also true of the other tasks we use, like groovydoc, or docgenerator.

that part is perfectly fine.

Now, let me explain why changing the strategy to use compiler N-1 is not necessarily a good idea for us: as I explained, Groovy also comes with a runtime. Say that in Groovy 3, we decide to get rid of call site caching, to only use invokedynamic. Then it means that the runtime of Groovy 3 will no longer include call site caching. However, the Groovy classes of the compiler would have been compiled with call site caching, so a _consumer_ of the compiler would fail, because those classes would no longer be there at runtime!

Of course one might say "then you can use the invokedynamic version" of Groovy to compile Groovy 3, which leads to the last bit of complexity of our build.

What you normally do is compiler with N-1 to get a compiler for N' and then use that compiler to get the real N. Very common strategy. Of course that means in a build where we would depend on an older release (N-1), we not be able to use features in the new version (N') before we have created N', which can actually compile the new features. And only then N could be compiled using the new features from N'. Using Java is kind of like saying we stay with N'. So there are pros and cons to this approach, it surely does not make things more easy from the build side. It would make the program code more easy and would be better in terms of "eat you own dog food".

what me really prevents from doing something like this is that the static compiler has to many fallbacks to dynamic code where I do not want them.

Some would have noticed that we now have a "testAll" task for each project. This task executes tests with the "indy" version of the compiler. Which means that in practice, we produce 2 versions of the compiler, not just one. This was the main reason for the complexity of the previous build, that I recently got rid of by using a different strategy and leveraging the Gradle build cache. So, instead of using the same outputs for both compilers, they are now separate, and we can run the tests in 2 flavors. The consequence is that tests are executed twice (one for `test`, the other for `testWithIndy`), but the outcome is much cleaner.

I hope this clarifies things a bit. Now for daily development, you can use:

./gradlew :test : will only execute the call site caching version of tests for the "core" project ./gradlew :testWithIndy : will only execute the indy version of tests for the "core" project ./gradlew :testAll : will execute both flavors of tests (indy and non indy) for the "core" project

And of course you can do the same for any subproject:

./gradlew :groovy-xml:test

You can also choose precisely which test to execute by adding `--tests *MyTest*` to the command line.

testAll and testWithIndy I did not realize,thanks.

bye Jcohen

Reply via email to